Collect Form Responses Without a Backend
You can collect form responses without a backend by letting the published page keep them. A page published on SnapHost carries a small built-in helper called window.SNAPHOST: one call appends an entry to a named collection, another reads entries back, and a contact form or a waitlist works with no server to run and no keys to manage.
That is the whole mechanic. Three things are worth five minutes before you build on it: who gets to read what people submit, what a stored entry says about who sent it, and where the limits are.
How to collect form responses without a backend
- Build the page with your assistant, form and all.
- Open the site's Data settings and pick a recipe (contact form, waitlist, RSVP, guestbook, shared counter, clock-in, scoreboard, leaderboard), or write the two calls yourself.
- Publish the page.
- Read the entries in the dashboard as they arrive.
Your assistant can do the same thing without you opening the dashboard at all: it can add the snippet to the page it just built for you. Collecting data is a Pro feature. On Free a page with a form in it still publishes and still looks right, but it cannot save or read anything, so the submit button goes nowhere. Better to know that before you build the form than after you send the link.
Why a form on an AI-built page usually goes nowhere
Ask an assistant for a page with a sign-up form and you get a good-looking form. What sits behind it is one of three things: a handler that pops up a thank-you and throws the answer away, a fetch to an API route that does not exist, or a paragraph telling you to set up a database and come back.
The other reflex is to paste in someone else's form. That does not work here, and it is worth knowing why. A published page's references to other origins are blocked by the delivered content policy: an outside script, stylesheet, font, frame, or network call. An embedded third-party form is a frame, so it does not render. When you publish, the page is scanned for exactly those references and they are reported back to you, though the scan is a convenience and the policy is what does the blocking. You can trust a specific origin for a site, which is on Pro. For a form there is a shorter road, because the page already has somewhere to put the answer.
The two calls that do the work
// Save a record. The collection is created on the first save.
await window.SNAPHOST.append('signups', { email: 'jane@acme.com' })
// Read records back, newest first.
const { records } = await window.SNAPHOST.query('signups', { order: 'desc', limit: 50 })
Data is grouped into named collections, and each saved item is a record. A collection name is letters, digits and the separators ., - and _, up to 128 characters, so signups and rsvp.dinner are both fine.
You mostly will not type this. The recipes set the data up and hand you a snippet, and the data docs carry both routes. Knowing the two calls is still useful, because it tells you what your assistant is doing when it wires a form for you. Those two calls also make a decision on your behalf, which is the next section.
Who can read what people submit
A collection has one setting that matters: who may read it. Private is the default, and it means visitors can add entries while only you can read them. That is the shape of a contact form or a waitlist, where one submission should not be visible to the next person who opens the page. Public means anyone who can open the page can read the collection, which is what a guestbook or a scoreboard needs to work at all.
When you publish or update a site, your page's code is read and new collections are set up to match it: a collection the page queries is made public so the page works on its first load, and one it only appends to stays private. The result tells you what was set up, and a choice you have made yourself is not overwritten by a later publish.
The honest gap is in the reading. That scan looks at the page and its scripts, and it matches a collection name written as a plain string. A name your page builds at runtime, or one reached through your own wrapper function, is invisible to it, by design. Nothing breaks: the collection keeps the private default, and if the page needed to read from it you set that yourself. It is the one case where a form works in testing and a public leaderboard comes up empty.
What a record says about who sent it
Every entry arrives with a small envelope stamped on the server before any of your own fields: the record's id, when it was appended, and who appended it. That last one is derived from the viewer's verified token and not from anything the page submitted, which is the part that makes it worth anything.
On a private site that is the viewer's verified email address. Each viewer confirms their address before access, so by the time they submit, the site already knows who they are, and an entry that says it came from dana@acme.com did. On a public site there is no identity, so entries are anonymous.
So on a public page, an email field is a claim someone typed. Treat it as one. If it matters who answered, put the page behind a list of addresses and read the stamped identity instead. The security page has the rest of how that gate works, including the record of who opened what.
The site's own privacy applies on top of the collection's setting. On a private site, only people who passed the access gate can add or read entries at all.
Reading the entries back, and changing one
Records are append-only. Nothing is edited in place: a correction arrives as a new record. To make that usable there is a fold that reduces a collection to the newest record per key field, so an RSVP someone changed their mind about twice still reads as one answer. You can also filter records by a field, sort them either direction, and page through them with a cursor.
The shape of your data is learned from the entries that have actually arrived, and you can fine-tune it in the Data tab. If you want, you can require every entry to match a set of rules so incomplete submissions are rejected as they come in rather than found later.
One rule when you put stored values back on the page: set them as plain text rather than as markup, so a value someone submitted can never run as code. The ready-made recipes already do this. It matters most for the collections meant to be read by visitors, a guestbook or a comment list, where the person submitting and the person reading are not the same person.
The limits, before you build on it
This is a store for small structured things, and the numbers say so plainly. A single record is capped at 64 KB once serialized, which is a form entry and not a document. A query hands back at most 200 records, 50 when you do not say. A site gets 50 collections by default, 100,000 records in each, and 1,000 key-value items. Pro includes 5 GB of storage overall, and you are warned as you approach a limit rather than finding entries missing.
Read those as the boundary of what this is for. Form entries, ratings, sign-ups, scores, a shared counter: yes. A file upload, a video, a dataset you meant to analyse: no, and the write is refused rather than quietly truncated.
What it costs
Free is three pages at a time, each public or private to up to three named people, served from sites.snaphost.ai with a small SnapHost mark. It does not include the data layer, so a form is the moment Free stops being enough.
Pro is 19 euros a month for each member who can publish, and readers are free however many there are. Data comes with it, along with version history, your own web address, and the longer allowlists. The pricing page is the current list.
What this does not replace
If you need to take payments, accept file uploads, or send a submission onward into a team inbox, this is not that, and a real form product will serve you better. This is for the case that keeps coming up once you build with AI: the page exists, it needs to remember four fields from twenty people, and standing up a backend for that is out of proportion to the job.
It pairs well with the pages you were publishing anyway. A prototype you are putting in front of testers can carry its own feedback form instead of a separate survey link, which is most of what user testing needs. A page you refresh weekly can collect a reply from each reader. The form ends up where the thing it is asking about lives, and people answer it there.