Editable content and forms
Let anyone in the workspace change words and pictures without a deploy, and collect form entries in Studio.
Declare content and forms
A site says which words and pictures people may edit, and which forms it takes, in a benchy.site.json file at the top of its output folder. Benchy reads it on each deploy. Content is grouped in collections: a single set of fields, such as the shop’s details, or a list of items with the same fields, such as prints.
{
"version": 1,
"content": {
"prints": {
"label": "Prints",
"list": true,
"fields": {
"title": { "type": "text", "label": "Name", "required": true },
"price": { "type": "number", "label": "Price" },
"photo": { "type": "image", "label": "Photo" },
"inStock": { "type": "boolean", "label": "In stock" }
}
},
"shop": {
"label": "Shop details",
"fields": {
"hours": { "type": "text", "label": "Opening hours" },
"about": { "type": "longtext", "label": "About us" }
}
}
},
"forms": {
"order": {
"label": "Order requests",
"fields": {
"name": { "type": "text", "required": true },
"email": { "type": "email", "required": true },
"print": { "type": "select", "options": ["Benchy", "Planter", "Lamp"] },
"message": { "type": "longtext" }
},
"redirect": "/thanks/"
}
}
}- Benchy looks for the file only at the top of the output folder, next to
index.html, never at the project’s root. "version": 1is optional; it names the format this page describes.- Names of collections, forms and fields use letters, digits,
-and_, and are case-sensitive:inStockandinstockare two fields.idis reserved, because every served list item carries its ownid. Eachlabelis what Studio shows. - A new field starts empty. A field you remove is hidden and its values kept, so rolling back to a version that had it brings them back.
- A deploy without
benchy.site.jsonserves no content: its/_benchy/content/addresses answer 404 until a deploy that has the file. Nothing is deleted, so the content comes back with it. - A deploy with an invalid
benchy.site.jsonis refused, and the error names the setting, such ascontent.prints.fields.photo.type. Only a JSON syntax error gives a line number.
| Content limit | Value |
|---|---|
| Collections per website | 20 |
| Forms per website | 20 |
| Fields in a collection | 40 |
| Options in a select field | 50 |
| A label | 80 characters |
| Items in a list | 1,000 |
| One item | 16 KB |
| Links in one item, each checked by Web Risk | 50 |
| One collection’s JSON | 4 MB |
| All content on a website | 16 MB, pictures not included |
Field types
| Type | Holds | Used in |
|---|---|---|
text | One line, up to 500 characters | Content and forms |
longtext | Plain paragraphs, up to 10,000 characters | Content and forms |
number | A number | Content and forms |
boolean | Yes or no; a checkbox in a form | Content and forms |
date | A calendar date | Content and forms |
email | An email address | Content and forms |
url | A web address | Content and forms |
select | One of the listed options | Content and forms |
image | A picture with its alt text, up to 25 MB | Content only |
A date is stored and served as YYYY-MM-DD, such as 2026-10-03.
Edit content in Studio
On the website’s page in Studio, Content shows one form per collection. Anyone with Can edit changes the words, adds, reorders and removes items, and uploads pictures, with no agent and no deploy. After Save, visitors get the change within 15 seconds, usually sooner.
- Content isn’t part of a version: rolling back the site keeps today’s content.
- Content text counts only against the website’s own 16 MB content limit, not the workspace’s storage. Pictures uploaded for content count toward the workspace’s storage.
- Each save is in the website’s history, with who made it.
Use content in your pages
Each collection is served on your own site at /_benchy/content/<collection>.json. A list collection is { "items": [...] } in the order set in Studio; a single one is an object of its fields.
const response = await fetch("/_benchy/content/prints.json");
const { items } = await response.json();
// items: [{ "id": "…", "title": "3DBenchy", "price": 12,
// "photo": { "url": "/_benchy/content/files/…", "width": 1200, "height": 900, "alt": "…" },
// "inStock": true }]A preview reads the live site’s content, shaped by the preview’s own benchy.site.json: a field the preview adds shows empty, and one it removes isn’t served. Pages that must show content without JavaScript can be rebuilt from it instead: pull it, build, and deploy.
Content from agents and the CLI
benchy site content pull olive-prints # writes content/prints.json and content/shop.json
benchy site content push olive-prints # saves your edited files as the site's contentAgents use site_content_get and site_content_set. Both need a key or app that can make changes in the workspace; a key that only publishes websites reads content but can’t change it.
Add a form
Declare the form in benchy.site.json, then post an ordinary HTML form to /_benchy/forms/<name> and include Benchy’s form script:
<form method="post" action="/_benchy/forms/order">
<label>Name <input name="name" required></label>
<label>Email <input name="email" type="email" required></label>
<label>Message <textarea name="message"></textarea></label>
<button>Send</button>
</form>
<script src="/_benchy/forms.js" defer></script>- The script adds a small spam check, served from
forms.benchy.site, so it works the same on a custom domain, and sets no cookies on your site. It also adds a hidden trap field. A form without the script is refused. - After a good entry the visitor goes to the form’s
redirectpage, or back to the same page with?sent=orderwhen there is none. - A form sent with
fetchandAccept: application/jsongets{ "ok": true }, or"ok": falsewith the fields that need fixing.
Read entries
Forms on the website’s page lists each form’s entries, newest first, with the page it was sent from. Owners and members with Can edit see them; Can view doesn’t, because entries hold people’s details.
- Export CSV downloads every entry, or those in a date range.
- Delete an entry at any time. Entries are deleted automatically after 90 days.
- Entries count toward the workspace’s monthly quota. See Plans.
benchy site forms export olive-prints order > orders.csv
benchy site forms export olive-prints order --since 2026-09-01 > september.csvAgents use site_forms_list and site_forms_export. Tell your visitors what you collect and why, on the page with the form.
Email notifications
Each member chooses Email me new entries on a form for themselves. The email is plain text, from forms@noreply.benchy.studio, with the form’s fields and the site’s address. Replying goes to the address in the entry’s email field, when it has one. A website sends at most 20 of these emails an hour; after that, one summary an hour lists the rest.
What forms accept
- Declared fields only, checked against their types and
required; anything else sent with the form is dropped. An entry is at most 32 KB of text, with no file uploads. - A form can’t ask for a password, payment details or a government ID number. A deploy that declares a password field, or fields for a card number, expiry date, security code or government ID number, is refused.
- One visitor can send 10 entries a minute to a site. Entries that fail the spam check are dropped and don’t count toward the quota.
- When a Free workspace reaches its monthly quota, its forms answer “This form isn’t taking entries right now” until the next month.
Use ← and → to move between pages.