Spam protection
The honeypot, rate limits, Allowed Origins and Turnstile.
Every Form runs a set of spam checks. Some are always on. You switch on the others Form by Form in its Spam tab.
A Submission the checks catch is stored as Spam, gets the same answer as a real
one (201, or the 303 redirect) and sends no Notification or webhook. It
waits 30 days and is then deleted. If something real was caught, mark it as not
spam in the dashboard: it moves to the inbox and its Notification goes out.
Files sent with a caught Submission aren't stored. Spam doesn't count towards
your Plan's monthly Submissions.
Honeypot
Add a field named _gotcha to your form and hide it from people. Bots fill in
every field they find, so a Submission with anything but whitespace in
_gotcha is Spam.
The name is the same one Formspree and Basin use, so forms moved from either keep working. The field is removed before the Submission is stored.
Rate limits
Always on, for every Form:
- 10 requests a minute from one visitor IP, across all Forms.
- 300 requests a minute to one Form, from everyone.
Past either limit the answer is 429 rate_limited with a Retry-After header
that says how many seconds to wait. Direct uploads have their own counters with
the same numbers. From a server, pass the visitor's IP in X-Visitor-IP with a
Submit Key so the limits count the visitor and not your
server.
Allowed Origins
Off by default, so any website can post to the Form. Add the sites that may
post and a browser post from any other site gets 403 origin_not_allowed.
Server-side submits with a valid Submit Key skip this check.
Each entry is a scheme, host and optional port, with no path. Enter
https://atelierondo.test, not https://atelierondo.test/contact. A bare
atelierondo.test is read as https://atelierondo.test. Matching is exact and
ignores case, so https://www.atelierondo.test is a separate entry, and
wildcards aren't supported. A Form can hold up to 50.
The check reads the request's Origin header, then Referer. A request that
sends neither is refused, which includes a page served with
Referrer-Policy: no-referrer. With Allowed Origins set, the CORS answer names
only the origin that asked, and only when it's on the list.
A Project can hold a default list of Allowed Origins that each new Form copies when it is created. Changing the default later doesn't touch existing Forms.
Cloudflare Turnstile
Switch Turnstile on and the endpoint asks Cloudflare to verify the token in the
cf-turnstile-response field, the name Turnstile's widget uses. A missing or
failing token gets 403 turnstile_failed, and nothing is stored. A Submit Key
doesn't skip this check: a server sending to such a Form has to forward the
visitor's token. Direct upload requests don't run the check, but the Submission
that names the uploaded files does.
The dashboard doesn't show a Turnstile site key for your widget yet. Until it does, keep Turnstile off: with it on and no widget on the page, every Submission is rejected.
Timing
The React library will send _elapsed, the milliseconds between the form
appearing and being sent. Under 1,500 counts as Spam. A request without it, or
with a value that isn't a number, skips this check, so plain forms aren't
affected.