Test

Form endpoint service: what 10 endpoints accept, tested

A form endpoint is a URL your form posts to. The service behind it keeps the message and sends it on, so your site needs no server code. We run one of these services, Formgong. So rather than tell you ours is best, we sent the same requests to ten of them and wrote down what came back.

Short answer: A form endpoint service is a hosted URL that takes your form's POST and delivers the message, usually by email. On 29 October 2026 none of the 9 endpoints that answered refused JSON, form-encoded or multipart bodies, and a browser fetch could read every one's answer. Only Web3Forms blocked our server-side posts.

Formgong·

How we tested

On 29 October 2026, between 14:12 and 14:26 UTC, we sent each of ten services the same requests with keys we made up, so nothing was stored or delivered. Every request carried a name, an email and a message. We posted them as JSON, as a form-encoded body and as multipart. We also sent the CORS preflight a browser sends before a JSON fetch, a plain HTML form post, and the same JSON from a server with no browser headers. The rules for reading each answer were written down before the first request. Requests went out with curl from a connection in Turkey. The browser check ran in Chromium on a page at example.com. We keep every raw answer and will send them to anyone who asks.

FormSubmit answered every request with Cloudflare error 521, which means its own server did not respond. We tried again 30 minutes later, and from a second network in Germany. Its home page returned 521 as well. That is an outage, not an answer about the form, so its row is empty.

JSON, form-encoded or multipart: what each endpoint read

Made-up keys, 29 October 2026. "Read": the key is a body field and the answer named that key, so the body was parsed. "Not refused": the key is in the URL, so the answer is about the form and does not prove the body was read.
ServiceKey goes inJSONForm-encodedMultipartAnswer to Accept: application/json
FormgongBody fieldReadReadReadJSON
FormspreeURLNot refusedNot refusedNot refusedJSON
Web3FormsBody fieldRead (browser)Blocked as a server callBlocked as a server callJSON
ForminitURLNot refusedNot refusedNot refusedJSON
BasinURLNot refusedNot refusedNot refusedJSON
FormSubmitURLNo answer (521)No answer (521)No answer (521)No answer
FormcarryURLNot refusedNot refusedNot refusedJSON
FormsparkURLNot refusedNot refusedNot refusedPlain text
Static FormsBody fieldReadReadReadJSON
SplitformsBody fieldReadReadReadJSON

No endpoint rejected any of the three formats, so you can post new FormData(form) or a JSON object to all of them. The difference is in what comes back. Formspark answered a JSON request with one line of plain text, so await res.json() throws on its error answers. Web3Forms treats any request without a real browser behind it as a server call, which is why curl got 403 for every format. From the browser it read the JSON body and named the bad key.

CORS: can a fetch from your own site read the answer

Preflight: OPTIONS from curl with Origin https://example.com, asking for POST and the content-type header. Last column: a real fetch with a JSON body from a page on example.com, 29 October 2026.
ServicePreflight statusAccess-Control-Allow-OriginAllows content-typePreflight cached forFetch from example.com
Formgong204*Yes1 dayReadable
Formspree200Echoes the originYesNot sentReadable
Web3Forms403 to curlNone to curlNone to curlNot sentReadable
Forminit200*YesNot sentReadable
Basin200*Yes2 hoursReadable
FormSubmitNo answer (521)Not tested
Formcarry204*Yes20 daysReadable
Formspark204*YesNot sentReadable
Static Forms200*Yes1 dayReadable
Splitforms204*Yes1 dayReadable

A fetch with a JSON body makes the browser ask the endpoint for permission first. If the endpoint says no, the browser never sends the post and your code gets only "Failed to fetch". All nine endpoints that answered gave that permission to any site. Web3Forms refused the preflight from curl but allowed it from the browser, the same server check as above. In our previous round, Jotform's submit address sent no CORS headers at all, which is why it is not on this list.

What a plain HTML form gets back

Form-encoded post with the Accept header Chrome sends, redirects not followed, 29 October 2026.
ServiceStatusWhat the visitor would see
Formgong303 redirectAn error page on formgong.com naming the problem
Formspree404An HTML page: form not found
Web3Forms403 (curl is treated as a server)In round 2, from Chrome: an error page, invalid key
Forminit200An HTML page: form deleted
Basin200An HTML page: endpoint locked
FormSubmitNo answer (521)
Formcarry200An HTML page: form is invalid
Formspark404One line of plain text: form does not exist
Static Forms401Plain text: Invalid API key
Splitforms404An HTML page: form setup issue

A form with action and method="POST" and no JavaScript navigates to whatever the endpoint answers. Every service that answered showed some kind of error for a wrong key. Formgong is the only one here that redirects with 303 to an error page. The others answer with the page itself. Forminit, Basin and Formcarry send that error page with status 200. A visitor will not notice, but an uptime check or a test that only looks at the status will report a broken form as working.

Posting from a server

We sent the same JSON with no Origin, no Referer and curl's own user agent, the way a backend, a cron job or a serverless function would. Eight of the nine that answered gave the same answer as from the browser. Web3Forms answered 403: "Use our API in client side or contact support with server IP address (Pro plan is required)".

Some services discourage server posts even where they work. Formcarry's docs say to post from the browser because every visitor would share your server's IP against its limit of one post per 15 seconds. Forminit offers a separate protected mode with an API key for servers. Formgong takes server posts on every plan. The contact form API page has the rate limits we measured.

What to check before you pick one

  • Posting from your server or a serverless function: avoid Web3Forms unless you are on its paid plan with an allow-listed IP. Mind Formcarry's per-IP limit.
  • A JavaScript form that reads the answer: any of the nine works with CORS, but plan for Formspark's plain-text errors and Forminit's 200 status on errors.
  • A plain HTML form with no JavaScript: all of them showed the visitor some kind of error for a broken key, so any of them will do.
  • Uptime monitoring on the form: pick one that answers errors with an error status. Forminit, Basin and Formcarry answered a broken form with 200 to a plain post.

For free plans, limits and where each one stores data, see our test of 13 form backends.

What this test does not show

Made-up keys show how an endpoint fails, not how it delivers. We did not measure how fast mail arrives, spam filtering, or what a successful post returns, because that needs a real form on each service. Every answer here was seen once on 29 October 2026 from one place. Services change, and each one's own docs are the final word.

Tell us what to test next

Is a service missing, or did one of them answer you differently? Write to support@formgong.com and tell us what you saw. We read every message, and the next round of this test starts from what readers ask for.

Questions

What is a form endpoint service?

A hosted URL that accepts a form's POST, stores the message and sends it to you, usually by email. You put the URL in the form's action attribute or in a fetch call, and your site needs no server code of its own.

Does a form endpoint accept JSON?

All nine services that answered our 29 October 2026 test accepted a JSON body: Formgong, Formspree, Web3Forms, Forminit, Basin, Formcarry, Formspark, Static Forms and Splitforms. None refused form-encoded or multipart either. Formspark answered JSON requests with plain-text errors.

Can I post to a form endpoint from my server?

Eight of the nine that answered on 29 October 2026 treated a server post like a browser post. Web3Forms answered 403 and asks for a paid plan and an allow-listed server IP.

Why does my fetch to a form endpoint say Failed to fetch?

Usually the CORS preflight was refused, the endpoint is down, or an ad blocker stopped the request. All nine endpoints that answered our test allow cross-origin fetch, so check the browser console for the exact reason and the address for typos.

Sources

Checked on 29.10.2026 against these public pages: Formspree: system limits, Formspree: submit forms with JavaScript, Web3Forms API reference, Forminit: submit form API, Forminit llms.txt, Basin docs, FormSubmit documentation, Formcarry llms.txt, Formspark: AJAX, Static Forms, Splitforms docs, MDN: CORS preflight request, Formgong API reference (llms.txt).

← Formgong