Forms
Every site on slew accepts form submissions — static sites included, with no JavaScript and no backend. Point any HTML form at /_slew/forms/<name> on your own site:
<form action="/_slew/forms/contact" method="POST">
<input name="email" type="email" required>
<textarea name="message"></textarea>
<input name="_gotcha" style="display:none" tabindex="-1" autocomplete="off">
<button>Send</button>
</form>
That's the whole integration. The form registers itself at the first submission — nothing to declare at build time, so a form rendered by JavaScript works exactly like one in static HTML. Submissions land in the console's Forms tab, and the project's owners get an email.
The endpoint is on your site's own origin (yoursite.com/_slew/forms/contact), so there is no CORS, no third-party domain in your HTML, and it works the same on custom domains, <project>.slew.cloud, and branch domains.
Forms are included in every plan. Submissions are stored in the EU, like everything else on slew.
What happens after submit
- Browser (HTML) submissions are answered with a redirect: to the path in a hidden
_nextfield if you add one (<input type="hidden" name="_next" value="/thanks">), else back to the page the form was on, else a minimal confirmation page._nextmust be a path on your own site. - JSON clients (
Content-Type: application/json, or anAccept: application/jsonheader) get{ "ok": true }— forfetch()-based forms:
await fetch('/_slew/forms/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
})
Field names starting with _ are reserved for form controls and never stored.
Spam
The _gotcha field in the example is a honeypot: hide it with CSS, and anything that fills it is answered with a fake success and stored nowhere. Submissions are also rate-limited per visitor address.
If a form still attracts junk, notifications can be switched off while you keep collecting, and individual submissions deleted from the console.
Notifications
New submissions are emailed to the project's owners (for an org project: every org owner) within a minute, batched — a burst of submissions is one email. Per form you can:
- route notifications to a different address (a shared inbox, a client),
- or turn them off entirely; submissions keep landing in the console.
Retention and GDPR
Form submissions are usually personal data. Slew stores them in the EU and gives you the controls a processor should:
- Retention: set a per-form window (say 90 days) and older submissions are deleted automatically. No window = kept until you delete them.
- Export: any form's full history as CSV, from the console or
slew forms export. - Delete: individual submissions or the whole form, from the console, CLI or API.
No visitor IP addresses or user agents are stored with submissions — only the fields your form sent and the page path it was on.
Limits
| Submissions per month | Free 100 · Pro 1,000 · Scale 5,000 · Studio 20,000 (per account or org) |
| Forms per project | 20 |
| Fields per submission | 100 |
| Submission size | 32 KB |
| File uploads | Not stored — file inputs are ignored, the rest of the form goes through |
At the monthly cap further submissions are refused with an explanatory page (they are stored data, not traffic — unlike bandwidth, which never hard-stops).
CLI
slew forms # list forms and submission counts
slew forms submissions contact # recent submissions
slew forms export contact > contact.csv
slew forms notify contact clients@agency.example
slew forms retention contact 90
slew forms rm contact
HTTP API
Ingest is unauthenticated on your site's origin: POST /_slew/forms/<name> with application/x-www-form-urlencoded, multipart/form-data, or application/json.
Management, with Bearer auth like everything else:
| Method | Path | Description |
|---|---|---|
GET |
/projects/:name/forms |
The project's forms with submission counts |
GET |
/projects/:name/forms/:form/submissions |
Submissions, newest first — ?limit= (max 200) and ?before=<timestamp> to page |
GET |
/projects/:name/forms/:form/export |
Full history as CSV |
PATCH |
/projects/:name/forms/:form |
Settings — { "notify"?, "notifyEmail"?, "retentionDays"? } |
DELETE |
/projects/:name/forms/:form |
Delete the form and its submissions |
DELETE |
/projects/:name/forms/:form/submissions/:id |
Delete one submission |
Errors on ingest:
| Code | Meaning |
|---|---|
invalid_form_name |
Names are lowercase letters, digits, - and _, at most 64 characters |
empty_submission |
No storable fields (everything was reserved or missing) |
too_large |
Over 32 KB of data |
rate_limit_exceeded |
Too many submissions from one address — wait a few minutes |
form_limit_reached |
The project already has 20 forms |
form_over_quota |
The plan's monthly submissions are used up |