How to Add a Contact Form to a Static Site (Without a Backend)
LaunchDir Team9 min read
You build the site. Astro, or Next.js exported static, or Framer, or something an AI assistant generated for you in an afternoon. It deploys to a CDN, it loads instantly, it costs nothing to host. Then you add a contact form, click submit to test it, and the page reloads with your fields smeared across the URL bar.
There is nowhere for the data to go. Static sites do not have a backend, which is the entire reason they are fast and free — and the one thing a form fundamentally needs.
This catches people out constantly, and the usual advice ("just add a serverless function") quietly understates the work. Here is what the job actually involves, and the shortest honest path through it.
Why a contact form is harder than it looks
A form feels like it should be twenty minutes. Accept a POST, send an email, done. In practice you are signing up for five separate small projects.
Somewhere to receive the POST. A serverless function, an edge route, a tiny server. Fine — this part really is twenty minutes.
Email that actually arrives. This is the one that bites. You cannot send mail from a serverless function without a provider, so now you are configuring an SMTP service or an API, verifying a sending domain, and setting up SPF, DKIM and DMARC records. Skip any of that and your form notifications land in spam, silently, and you find out weeks later when someone asks why you never replied.
Spam filtering. Within days of going live, bots will find your form. Not a trickle — a constant drip of SEO pitches and gibberish, enough that you stop reading the notifications, which defeats the point of having the form.
File storage, if you accept attachments. Resumes and screenshots have to go somewhere private, with signed URLs so they are not world-readable.
Retries and retention. The webhook you forward to will be down sometimes. And if any of your visitors are in the EU, "how long do you keep this and can you delete it" is a question you need an answer to.
Each one is small. Together they are a week you did not plan on spending, for a contact form.
The options, honestly
A mailto: link. Zero infrastructure, and it works — for the subset of visitors with a desktop mail client configured. For everyone else it opens nothing, or opens a webmail compose window they abandon. It also publishes your address for scrapers. Fine for a personal page, lossy for anything that matters.
Embedding Google Forms. Free and genuinely reliable. The cost is that it looks like Google Forms, sits in an iframe you cannot style, and breaks the visual flow of a site you spent a weekend designing.
Rolling your own. The right call when the form is load-bearing — payments, complex validation, writing into your own database. For a contact form, you are building and then maintaining the five things above, forever, to receive maybe forty messages a month.
A form backend. A hosted endpoint that receives the POST for you. You keep your own HTML and your own design; someone else runs the deliverability, spam filtering and storage. For the overwhelming majority of contact, feedback, waitlist and job-application forms, this is the correct answer, and it is the one most people arrive at eventually.
How a form backend actually works
The mechanism is simpler than the name suggests. You get a unique URL, you point your form's action at it, and that is the integration.
<form action="https://formsubmit.app/f/your-form-id" method="POST">
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<!-- Honeypot: bots fill it, people never see it -->
<input type="text" name="_honey" style="display:none" />
<button type="submit">Send</button>
</form>
No JavaScript, no build step, no dependency. It works in a plain HTML file opened from disk, and it works identically inside React, Vue, Astro, WordPress or a page some AI tool generated for you — because at the end of all of those is still an HTML form element.
If you want to stay on the page and show your own success state, post it with fetch instead and handle the JSON:
That is the whole surface area. Everything else a form backend does happens after the request lands.
FormSubmit: one endpoint, every integration on every plan
FormSubmit is a form backend built around exactly that idea — you keep full control of your form's markup and design, and it runs the infrastructure behind it. Sign up, create a form, and you get an endpoint like formsubmit.app/f/k3m9p2qabx to paste into your action. It is about a minute from signup to a working form.
What is unusual is the plan structure. Every feature is included on every plan, including the free one: email notifications to you and any teammates, spam protection, file uploads, webhooks, an autoresponder that thanks the person who submitted, a domain allowlist so only your own sites can post to your endpoint, and integrations with Slack, Discord and Google Sheets. There is no tier that withholds webhooks until you pay. What you choose is volume — the free plan covers 1 form, 50 submissions a month and 100 MB of files, and paid plans start at $5/month with two months free on yearly billing.
The spam handling is layered and mostly invisible: a honeypot field, a time-to-submit check, content scoring with adjustable sensitivity, duplicate detection and per-IP rate limiting, with reCAPTCHA, hCaptcha or Turnstile available if you want them. Crucially, most bots get caught by the silent checks, so real people are not made to solve puzzles. Anything suspicious lands in a separate Spam folder and does not count against your quota, which matters more than it sounds — plenty of services will happily burn your monthly allowance on bot traffic.
Two details worth singling out. The Google Sheets integration requests only the drive.file scope, meaning it can touch the spreadsheets it creates for you and nothing else in your Drive — a meaningfully narrower permission than most tools ask for. And retention is per-form: keep submissions forever, for a fixed window of 7 to 365 days, or never store them at all and forward straight to email and integrations. If you have been putting off a GDPR answer, that last option is the simplest one there is.
There is also a visual builder that exports code for 13 frameworks, and a hosted form page at formsubmit.app/to/your-form if you need to collect something and do not have a site to put it on yet.
Best for: anyone shipping a static, JAMstack, no-code or AI-generated site who needs forms that reliably arrive and does not want to run mail infrastructure to get them.
What to check before you pick one
The category has a lot of entrants and they differ in ways that are not obvious from the pricing page. Four questions separate them.
What happens when you hit the limit? The answer you want is "nothing is lost". Some services silently drop submissions past your quota, which is the worst possible failure mode — you never know what you missed. Storing them and locking them until you upgrade is the humane version.
Does spam count against your quota? If it does, your plan is partly funding bots.
What permission does the Google integration ask for? "See, edit, create and delete all your Google Drive files" is a very common ask for something that needs to write one spreadsheet. Narrow scopes exist; prefer the services that use them.
Can you turn storage off? Forwarding without retention is the cleanest privacy posture available, and plenty of tools do not offer it.
Then make the form worth filling in
Once the plumbing works, the remaining problem is a copywriting one. Most contact forms underperform because they ask for too much — a phone number nobody wants to give, a dropdown of enquiry types that exists for your routing convenience rather than the visitor's benefit. Three fields converts better than seven, essentially always. If people are reaching your page and not submitting, the issue is usually further up the page than the form.
It is also worth writing a real page around it rather than a bare form. A page that answers the questions people actually ask gets found, gets linked, and increasingly gets quoted back by AI assistants when someone asks for a recommendation in your category — which a contact form on its own never will.
And when the thing you built is ready for people to see, launch it here. It is free, it takes about two minutes, and you get a permanent page with a followed link back to your site.
Frequently Asked Questions
Can I add a form to a static site without any backend at all?
Yes. Point your form's action at a hosted form backend endpoint — FormSubmit gives you one on signup — and set method="POST". No server, no serverless function, and no JavaScript unless you want to handle the response in your own UI.
Will form notification emails land in spam?
They can, if you send them yourself without configuring SPF, DKIM and DMARC for your sending domain. This is the single most common reason a self-built contact form appears to work in testing and then quietly fails in production. A form backend handles sending reputation for you.
How do I stop spam without making visitors solve a captcha?
A honeypot field plus a time-to-submit check catches the large majority of automated submissions invisibly. Reserve a visible captcha for forms that are still getting through after that — every captcha you add costs you real submissions too.
Is a form backend the same as a form builder?
No, and the distinction matters when you are shopping. A form builder like Typeform or Google Forms gives you the form itself, hosted and styled by them. A form backend gives you only the receiving end, so you write and style the form yourself. If you want to design your own form, you want a backend; if you want someone else to design it, you want a builder.
What about file uploads?
Most form backends support them, but check where files are stored and whether they are publicly addressable. You want private storage with signed, expiring links — particularly for anything like a CV or an ID document.