# User Generated Content (UGC)

> Source: https://agilitycms.com/docs/developers/user-generated-content-ugc

> [!IMPORTANT]
> UGC is a legacy service. It's still supported for existing websites, but it gets no new features and we don't sell it for new projects. If you're building something new, skip to [What to use instead](#what-to-use-instead).

User Generated Content (UGC) is a separate Agility service for storing content that **your website's visitors** create: form submissions, comments, ratings, likes and votes, uploaded files, and website user profiles. It's separate from the content your editors manage in Agility, and it has its own API at `ugc.agilitycms.com`.

Most websites used UGC for one thing: **saving form submissions**, like contact forms, feedback forms and sign-ups.

## How UGC works

### Record types and records

UGC stores **records**. Each record belongs to a **record type**, which defines its fields, much like a content model does for regular content. A contact form, for example, would have a `ContactSubmission` record type with fields for name, email and message.

Every record has a **state**: `New`, `Published`, `Draft`, `AwaitingReview`, `Escalated`, `Declined`, `Processing`, `Error` or `Deleted`. This is how moderation works. A record type can publish new records automatically, or hold them for someone to review first.

Records can also carry comments, feedback (ratings, likes, votes and approve/disapprove) and files.

### Access keys and the access hash

Each website gets a UGC **Access Key** and **Secret Key**. If you don't have yours, contact [support@agilitycms.com](mailto:support@agilitycms.com).

Calls from the browser are signed with an **access hash**, which your server computes so the Secret Key never reaches the browser. The hash is the SHA-1 of these values, joined with dots:

```text
[seconds].[profileRecordID].[secretKey].[accessKey].[random]
```

- `seconds`: seconds elapsed since January 1, 2001
- `profileRecordID`: the signed-in website user's profile record ID, or `-1` for an anonymous visitor
- `random`: a random number from 1 to 1000

Your server puts the result, without the Secret Key, into a global `_AgilityUGCSettings` object on the page:

```javascript
var _AgilityUGCSettings = {
  Url: "https://ugc.agilitycms.com/Agility-UGC-API-JSONP.svc",
  AccessKey: "YOUR-ACCESS-KEY",
  Seconds: "567353588",
  RandomNumber: "205",
  ProfileRecordID: "-1",
  AccessHash: "THE-SHA1-HASH"
};
```

### The JavaScript SDK

The [`agility-ugc`](https://www.npmjs.com/package/agility-ugc) package is a browser-only client for the UGC API. It picks up `_AgilityUGCSettings` automatically.

```bash
npm install agility-ugc
```

Saving and searching records looks like this:

```javascript
import ugcClient from "agility-ugc";

const searchArg = new ugcClient.SearchArg();
searchArg.RecordTypeName = "ContactSubmission";
searchArg.PageSize = 10;
searchArg.RecordOffset = 0;

ugcClient.SearchRecords(searchArg, (data) => {
  if (data.ResponseType !== ugcClient.ResponseType.OK) {
    console.error(data.Message);
    return;
  }
  const { Records, TotalRecords } = data.ResponseData;
});
```

The main methods are:

| Task | Methods |
|---|---|
| Records | `SaveRecord`, `GetRecord`, `SearchRecords`, `DeleteRecord`, `SetRecordState` |
| Record types | `GetAllRecordTypes`, `GetRecordTypeByName`, `SaveRecordType` |
| Comments and feedback | `SearchComments`, `SaveRating`, `SaveLike`, `SaveVote`, `GetFeedbackAggregate` |
| Files | `GetUGCUploadForm`, `UploadFile`, `DeleteFile` |
| Website users | `Authenticate`, `IsAuthenticated`, `Logout`, `ChangePassword`, `RetrievePassword` |

Every method is asynchronous and takes a callback. Check `data.ResponseType` before you use `data.ResponseData`.

## What to use instead

If you're using UGC for forms, or about to, there's a better option today. Let a form provider handle the form, or send submissions straight to the system your team already works in. You get spam protection, notifications, reporting and integrations without having to build them.

### A form provider

Build the form in a form tool, and let editors place it on any page in Agility with an app:

- [Formstack](/docs/apps/formstack)
- [Typeform](/docs/apps/typeform)

Using a different form provider? Most of them give you an embed code or a form ID, so it's easy to hook up with a custom field or a small app (see [Connecting something else](#connecting-something-else)).

### Your CRM, directly

If submissions end up in your CRM anyway, skip the middle step and send them there:

- [HubSpot](/docs/apps/hubspot): build the form in HubSpot and pick it in Agility.
- [Salesforce Web-to-Lead](/docs/apps/salesforce-web-to-lead): turn a Salesforce web-to-lead form into a form on your site.
- [Salesforce Sales Cloud](/docs/developers/salesforce-sales-cloud): create Salesforce contacts from your own form through a small backend.

The same pattern works for any CRM with an API. Post the form to a server route on your website, and have the route call the CRM.

### Connecting something else

If there's no app for your tool yet, you can build one. Apps run inside Agility and can add custom fields, so editors pick a form from a list instead of pasting IDs. See [Creating Apps for Agility](/docs/apps/creating-apps-for-agility). Need to react when content changes instead? Use [webhooks](/docs/developers/webhooks).

## Moving off UGC

You don't have to move. UGC is still supported. When you're ready:

1. **Pick where new submissions go**: a form provider or your CRM, from the options above.
2. **Rebuild the form** there, and swap it onto your pages in Agility.
3. **Keep what you already collected.** Read your existing records with `SearchRecords` and import them into the new system, if you still need them.
4. **Remove the UGC code** from your website, including the server code that computes the access hash.

Have questions about your UGC setup? Contact [support@agilitycms.com](mailto:support@agilitycms.com).

---

## Related pages

- [Zapier Translate](https://agilitycms.com/docs/developers/zapier-translate.md)
- [Vercel](https://agilitycms.com/docs/developers/vercel.md)
- [Ahrefs](https://agilitycms.com/docs/developers/ahrefs.md)
- [Netlify](https://agilitycms.com/docs/developers/netlify.md)
- [Salesforce Sales Cloud](https://agilitycms.com/docs/developers/salesforce-sales-cloud.md)
- [Auth](https://agilitycms.com/docs/developers/auth0.md)

Index of every docs page: https://agilitycms.com/docs/llms.txt
