Contact form for any HTML website
The simplest possible setup. Drop one `
What your HTML contact form actually looks like.
Drop-in form backend with spam filtering, signed webhooks, and a real submissions dashboard. The same code in this preview is what you copy into your HTML project — no SDK, no plugin, no PHP.
- ✓1,000 submissions per month, free forever
- ✓Honeypot + AI spam classifier on every plan
- ✓Signed webhooks to Slack, Discord, your server
Ship a HTML contact form without a backend.
No SDK, no PHP, no plugin. Your form posts standard FormData to one URL — submissions land in your inbox.
Get your free access key
Verify your email and your access key is generated instantly. Free for 1,000 submissions per month, forever.
By signing up, you agree to our terms and privacy policy.
Drop in the HTML code
Copy the HTML snippet on the right and paste it into your project. Replace YOUR_ACCESS_KEY with the key from step 1.
Submissions land in your inbox
Hits your dashboard and email in seconds. Forward to Slack, Discord, Sheets, Notion, or any signed webhook URL.
Try it now — no signup, no key.
This is a styled HTML preview of what your HTML form will look like. Submitting opens a confirmation, no real request is sent.
Your HTML form posts FormData to /api/submit. Splitforms validates the access key, runs the spam classifier, and forwards the parsed submission to your inbox plus the dashboard.
- →14ms median round-trip from the edge.
- →Honeypot + classifier, no CAPTCHA.
- →Per-domain key locking out of the box.
{
"access_key": "sk_live_4f9a_••••",
"name": "Maya Iyer",
"email": "maya@studio71.co",
"message": "…"
}How to ship this without regrets.
Five rules that make the difference between a form that works in the demo and a form that survives launch traffic.
- 01
Always set `method="POST"` explicitly. The HTML default is GET, which won't work with splitforms.
- 02
Add a `redirect` hidden field pointing to a `/thanks.html` page so users without JS still get a confirmation page after submitting.
- 03
Lock the access key to your domain in the splitforms dashboard. The key lives in your HTML source — anyone can copy it, but domain locking makes it inert elsewhere.
- 04
Use `required` attributes on essential inputs. Browsers enforce these client-side without JavaScript — gives users immediate feedback if they forget a field.
- 05
Add `autocomplete="name|email|tel|…"` attributes to inputs. Browsers fill them automatically, dramatically improving conversion on mobile.
What bites people who skip the docs.
Worth a 60-second skim before you ship to production. Each one has caused a HTML support ticket at least once.
method="GET" turns your form into a URL query string
If you forget method="POST" (or omit it — GET is the HTML default), the browser appends form fields to the URL: ?name=Maya&email=…. Splitforms's endpoint returns 405 Method Not Allowed because it only accepts POST. Always specify the method explicitly.
Multiple inputs with the same `name` only send the last value
If you accidentally name two fields email, FormData posts both — but the splitforms dashboard shows the last one. For checkbox groups, use name="interests[]" or unique names per checkbox.
File inputs require enctype="multipart/form-data"
Standard forms submit as application/x-www-form-urlencoded, which can't carry binary file data. If you add <input type="file">, also add enctype="multipart/form-data" to the form tag — otherwise the file silently doesn't upload.
Hidden honeypot field needs to be invisible to bots' DOM parsers
style="display:none" is what splitforms uses, but some sophisticated bots ignore display:none. Stack defenses: display:none + tabindex="-1" + aria-hidden="true" + an off-screen label. Splitforms's classifier catches the rest.
GitHub Pages can't post to https without HTTPS on your domain
Mixed-content errors: if your GitHub Pages site is served over HTTP (rare but possible on custom domains without HTTPS toggled), the browser blocks the POST to https://splitforms.com. Enforce HTTPS in your custom domain settings.
<button> outside the <form> tag does nothing on submit
Browsers only treat a button as a submit trigger when it's a descendant of the form element. If your CSS layout requires the submit button to live outside the <form> (e.g. a sticky bar at the page bottom), the form will never submit on click — Enter inside an input still works. Fix it by adding form="contact-form" on the button, matching an id="contact-form" on the form. The HTML5 form-attribute association is widely supported but easy to forget.
How HTML handles forms without splitforms.
The shape of the problem before splitforms enters the picture — and the gap it fills for HTML specifically.
Plain HTML has no built-in way to deliver a form submission anywhere — the spec only covers serializing fields and either GETting or POSTing them to whatever URL you put in action. Without a backend, the historical fallback is mailto: links (broken on Gmail, Outlook web, and most mobile devices) or PHP on shared hosts (extinct on S3, GitHub Pages, Cloudflare Pages, Netlify-static). That's the gap splitforms fills: you keep using the same <form action method=POST> HTML you already wrote, and the action points at our endpoint instead of a server you'd otherwise have to operate.
Two ways to ship splitforms on HTML.
Pick the pattern that matches your constraints — JS budget, key-exposure tolerance, server-side opacity. Both produce the same result.
Pattern A — pure HTML with redirect-on-success
The simplest possible setup: zero JavaScript, full graceful degradation, the browser handles the round-trip. Splitforms 302s to your redirect URL on success, so users always land on a thank-you page even with JavaScript disabled or a flaky network.
Pattern B — HTML with progressive-enhancement fetch
Same HTML, plus a tiny inline <script> that intercepts the submit, posts via fetch, and renders inline status — without a framework. Falls back to native form behaviour if JS fails to load.
Shipping HTML + splitforms to production.
Host-specific gotchas, env-var conventions, and the boring-but-load-bearing details for putting this on the public internet.
Plain HTML deploys to anywhere that serves files: GitHub Pages, S3 + CloudFront, Cloudflare Pages, Netlify, Vercel, plain Apache/nginx, even Dropbox public folders (RIP). The form posts cross-origin from the browser to splitforms.com, so the host is irrelevant to delivery — but enforce HTTPS on your domain, otherwise the browser blocks the mixed-content POST. On GitHub Pages, toggle 'Enforce HTTPS' under Settings → Pages. On S3, terminate TLS at CloudFront. Lock the splitforms access key to your custom domain in the dashboard so a leaked key from View Source is inert elsewhere.
splitforms vs native html.
What you get for free vs what you build, pay for, or do without.
Things developers ask before they integrate.
Direct answers, no marketing fluff. Missing one? Email hello@splitforms.com.
Ship your HTML contact form in 60 seconds.
1,000 free submissions per month. No credit card. Lock the access key to your domains, paste the snippet, watch submissions land in your inbox.
