Static Website Forms: 5 Ways to Add a Form Without a Backend
Static website forms need somewhere to send data. Compare mailto, form backends, serverless functions, platform forms and embeds, plus a step-by-step example.
5 min read

Static website forms need an external service to receive submissions, because static hosts only serve files and cannot run code when someone clicks submit. The simplest fix is to point your form's action at a hosted form backend; alternatives include a serverless function, your host's built-in forms, or an embedded form builder. The mailto: trick technically works but is unreliable.
This guide explains why forms on static sites break, compares the five options, and walks through adding a working contact form in a few minutes.
Why static sites cannot process forms
A static site is a folder of HTML, CSS, JavaScript and images. Hosts like GitHub Pages, Cloudflare Pages or an S3 bucket return those files when a browser asks for them. That is all they do.
Processing a form takes more. When a visitor submits, something has to:
- Accept an HTTP
POSTrequest - Parse the fields and any uploaded files
- Check for spam
- Send an email or store the data somewhere
- Respond with a redirect or a message
With no backend, there is nothing to do those steps. That is why a form on a static host that posts to its own page often returns a 405 "Method Not Allowed" error, or simply reloads with nothing sent.
Five ways to add a form to a static website
1. A mailto form
Setting action="mailto:you@example.com" asks the visitor's computer to open an email app with the form data. It needs no service at all, but it fails for anyone without a configured mail client, gives no confirmation and exposes your address to scrapers. We cover this in detail in mailto form vs form backend.
2. A hosted form backend
You keep your form markup and set its action to a URL provided by a form backend service. The service handles spam, storage, email notifications and integrations. It works on every static host and with every static site generator. See what is a headless form backend for how the request flow works.
3. A serverless function
Hosts like Netlify, Vercel and Cloudflare let you deploy functions next to your static files. You write the handler, connect a transactional email provider and add your own spam checks. Full control, more maintenance.
4. Platform forms
Some hosts, Netlify being the best-known example, can detect forms in your HTML at deploy time and collect submissions for you. It is quick if you already host there, but the form only works on that platform.
5. An embedded form builder
Tools like Google Forms, Typeform or Tally host the form and let you embed it, often in an iframe. Good for surveys and multi-step flows, but the form does not inherit your site's styles and lives partly outside your page.
Static website forms: comparing the options
| Option | Setup effort | Works on any host | Reliable delivery | Spam protection | Design control |
|---|---|---|---|---|---|
| mailto form | Minimal | Yes | No | None | Full |
| Hosted form backend | Low | Yes | Yes | Built in | Full |
| Serverless function | Medium to high | Only hosts with functions | Depends on your setup | You build it | Full |
| Platform forms | Low | Only that host | Yes | Varies by platform | Full |
| Embedded form builder | Low | Yes | Yes | Built in | Limited |
For most static site contact forms, a hosted backend gives the best balance: no backend code to maintain, and the form stays native HTML that you can style however you like.
Step by step: a static site contact form
Here is the full process using a hosted endpoint. It works on any host because the browser posts directly to the service.
- Create a form with a form backend service and copy its endpoint URL.
- Add the HTML below to your page, replacing
YOUR_FORM_ID. - Make sure every field has a
nameattribute; unnamed fields are not sent. - Deploy your site and submit a test entry.
- Check your inbox (and spam folder the first time) for the notification.
<form action="https://formsubmit.app/f/YOUR_FORM_ID" method="POST">
<label for="name">Name</label>
<input id="name" type="text" name="name" autocomplete="name" required>
<label for="email">Email</label>
<input id="email" type="email" name="email" autocomplete="email" required>
<label for="message">Message</label>
<textarea id="message" name="message" rows="5" required></textarea>
<input type="hidden" name="_subject" value="New message from the website">
<input type="hidden" name="_redirect" value="https://example.com/thanks">
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off" style="display:none">
<button type="submit">Send message</button>
</form>The three control fields are optional: _subject sets the notification subject, _redirect sends visitors to your own thank-you page, and _gotcha is a honeypot that silently catches bots. The full list is in the control fields docs.
Optional: submit without a page reload
If you want an inline success message, intercept the submit and use fetch:
const form = document.querySelector("form");
form.addEventListener("submit", async (e) => {
e.preventDefault();
const res = await fetch(form.action, {
method: "POST",
body: new FormData(form),
headers: { Accept: "application/json" },
});
const result = await res.json();
form.innerHTML = result.ok
? "<p>Thanks, your message was sent.</p>"
: "<p>Something went wrong. Please try again.</p>";
});A JSON response looks like { "ok": true, "id": "…" } on success or { "ok": false, "error": { "code", "message" } } on failure.
Hosting notes
The HTML form above behaves the same everywhere, but each host has its own quirks.
- GitHub Pages: pure static hosting with no functions or form handling, so a hosted endpoint is the practical choice. Custom domains work as usual.
- Netlify: offers built-in forms and functions. If you use a third-party endpoint instead, make sure Netlify's form detection is not also trying to handle the same form.
- Vercel: static and framework sites can use serverless functions, or post to an external endpoint with no configuration.
- Cloudflare Pages: supports Pages Functions for custom handlers; external endpoints work without changes.
- Amazon S3 (with or without CloudFront): static files only. S3 does not accept form posts to your bucket, so an external endpoint is required.
Handling files and integrations
Static forms can do more than send email. With a form backend you can accept uploads by adding enctype="multipart/form-data" to the form and an input type="file"; see file uploads for limits. You can also forward submissions to tools like Google Sheets or Slack, or to your own API via webhooks, all without writing server code.
Get your static form live
FormSubmit is a headless form backend built for exactly this case: point your static website forms at a FormSubmit endpoint and you get spam protection, email notifications, uploads and integrations on every plan, including Free. Build a form visually with the free form generator, or follow the HTML contact form guide for more detail.
Last updated .


