Insane Forms

JavaScript fetch

Send Submissions from your front-end code and read the JSON answer.

Any framework can send a Submission with fetch. You keep full control of the form, its validation and what the visitor sees afterwards.

Send JSON

A request with a JSON body, or with Accept: application/json, gets JSON back instead of a redirect. The body has to be a JSON object. Its values can be strings, numbers, booleans, arrays or nested objects.

Send a form element

To send a <form> as it is, pass a FormData and ask for JSON:

FormData is sent as multipart, so this also works for forms with file inputs (see file uploads). Leave the Content-Type header out: the browser adds it, with the boundary.

Read the answer

A stored Submission answers 201:

Spam gets exactly the same answer, so a bot can't tell it was caught.

An error answers with a status code and a code you can branch on:

Always check result.ok rather than the HTTP status alone: a failed request still has a JSON body in this shape.

Gotchas

  • Send Accept: application/json. Without it, a urlencoded or multipart post gets the 303 redirect, and fetch follows it and hands you the thank-you page.
  • Send a Content-Type for a string body. fetch defaults to text/plain, which the endpoint refuses with 400 invalid_body.
  • The endpoint checks, in this order: the Form exists and is on, the Plan's monthly limit, the Submit Key, Allowed Origins, rate limits, the body, Turnstile, then the honeypot and timing. The first failure is the answer you get.

CORS

The endpoint answers CORS requests, preflight included, from any origin. Once a Form has Allowed Origins, only those origins can post to it from a browser. Allowed methods are POST and OPTIONS, and the only request header you can add is Content-Type. A browser can't send a Submit Key or X-Visitor-IP, which suits a key that has to stay secret.

On this page