> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getsite.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# CMS

> Collections of records your pages read and write through a small JavaScript SDK.

The CMS stores structured data per site: testimonials, menu items, job listings, anything you would otherwise hard-code. Pages read it with the `gscms` SDK, and visitors can submit records if you allow it. Developer plan and above.

Manage it under **Site settings → CMS & Files**.

## Collections

**Add collection** with a name. The slug is derived from it and used in the SDK. Each collection has three switches:

| | Default | |
| - | - | - |
| **Read** | On | Published pages can read approved records |
| **Write** | Off | Visitors can submit records |
| **Auto-approve** | Off | Visitor submissions go live without review |

Deleting a collection deletes its records.

## Records

A record is a JSON object. **Add record** offers a form mode (name and value rows, with a JSON toggle for numbers, booleans and lists) or raw JSON. Records you add are approved immediately. Visitor submissions are **Pending** until you **Approve** or **Reject** them, unless auto-approve is on. Filter by **All**, **Pending**, **Approved**, **Rejected**.

## Use it on a page

Once a site has at least one collection, every published page gets `window.gscms`. It is defined in `<head>` before your own scripts run, so call it directly:

```js theme={null}
async function load() {
  // Approved records, newest first. 20 per page by default, 100 max. Pages start at 0.
  const { records, total } = await gscms.list('testimonials', { limit: 20, page: 0 });

  // Each record is { _id, data, created_at }. Your fields are under data.
  records.forEach((r) => console.log(r.data.name, r.data.quote));

  // One record by id.
  const { record } = await gscms.get('testimonials', records[0]._id);

  // Submit a record. The collection must allow Write.
  // Resolves to { id, status } where status is "pending" or "approved".
  await gscms.create('testimonials', { name: 'Ana', quote: 'Great work.' });
}
load();
```

Every call rejects with an `Error` whose `.status` is `404` when the collection does not exist or Read is off, `403` when Write is off, `400` for invalid data and `429` when rate-limited or the collection is full.

To have the AI Developer render a collection, give it the call and the record shape: *fetch `gscms.list('testimonials')` and render each record's `data` as a card*.

To cut spam on public submissions, add a hidden honeypot field to the form; the SDK sends it and the server drops submissions that fill it in:

```html theme={null}
<input type="text" name="gs_hp" style="display:none" tabindex="-1" autocomplete="off">
```

Reads return approved records only and are cached for 60 seconds. Other websites cannot call the endpoints from a browser; approved records are still public to anyone who requests the URL directly.

## Limits

| | |
| - | - |
| Collections per site | 20 |
| Records per collection | 5,000 |
| Record size | 16 KB |
| Keys per record | 200, values nested at most 4 objects or arrays deep, key length 128 |
| Reads | 300 per IP per 5 minutes |
| Writes | 15 per IP per 10 minutes |

Keys cannot start with `$` or contain `.`; `__proto__`, `prototype` and `constructor` are rejected; top-level keys starting with `_gs_` are reserved and dropped. The SDK is not injected into drafts or previews.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.