Contact Form for Static Websites

Last updated: March 2026

A contact form for a static website is one of the most common problems developers face. Static sites are fast, secure, and cheap to host, but they can't process form submissions on their own. There's no server to receive POST requests, no database to store messages, and no mail function to forward them to your inbox.

A form backend fixes this. Point your HTML form's action attribute to an external API endpoint, and it handles everything: receiving submissions, storing them, filtering spam, and emailing you the results. You write the HTML. The backend does the rest.

Why static sites need a form backend

Static site generators like Astro, Hugo, Jekyll, Next.js (static export), Gatsby, and Eleventy produce plain HTML, CSS, and JavaScript files. These files get served from a CDN. There's no server-side runtime executing code when a visitor clicks "Send."

When someone submits an HTML form, the browser sends an HTTP POST request to the URL in the form's action attribute. On a traditional server-rendered site, your PHP, Node.js, or Python backend catches that request, processes the data, and sends an email. On a static site, there's nothing listening.

Without a backend, three things can happen when someone submits your form:

  • The browser tries to POST to the current page URL and gets a 405 Method Not Allowed error
  • The form submits but the data goes nowhere
  • You've set action="mailto:you@example.com", which opens the visitor's mail client instead of actually sending a message (and exposes your email to scrapers)

None of these are acceptable for a production site. You need something to receive and process that POST request.

How a form backend works

The data flow for a static site contact form is straightforward:

  1. Visitor fills out your form on your static site (hosted on any CDN)
  2. Browser sends a POST request to the form backend API endpoint (the URL in your form's action attribute)
  3. Form backend receives the data, validates it, checks for spam, and stores the submission
  4. Backend sends you an email notification with the form contents
  5. Visitor gets redirected to a thank-you page or sees a success message

Your static site never runs any server code. The CDN serves HTML files. The form backend API handles everything else over HTTPS.

Three approaches compared

There are three ways to handle form submissions on a static site. Here's how they stack up.

Option 1: Form backend service (FormWit, Formspree, etc.)

You add an action URL to your HTML form and the service handles the rest.

Pros:

  • Zero code beyond HTML
  • Setup takes under 5 minutes
  • Built-in spam filtering, email notifications, and a dashboard
  • No infrastructure to manage or monitor
  • Works on every hosting platform

Cons:

  • Free tiers have submission limits (FormWit: 100/month)
  • Third-party dependency for form processing

Option 2: Serverless function (AWS Lambda, Cloudflare Workers, Vercel Functions)

You write a function that receives the POST request, validates the data, and sends an email via an SMTP service or API like SendGrid.

Pros:

  • Full control over processing logic
  • Can integrate with any downstream system (CRM, database, Slack)
  • Pay-per-invocation pricing can be very cheap at low volume

Cons:

  • You write and maintain the function code
  • Need to set up email sending separately (SES, SendGrid, Resend)
  • Need to build your own spam protection
  • No dashboard for viewing submissions unless you build one
  • Cold starts can add 200-500ms latency on first request
  • Debugging production issues means reading cloud provider logs

Option 3: Self-hosted API server

You deploy a Node.js, Python, or Go server that exposes a POST endpoint for form submissions.

Pros:

  • Complete control over everything
  • No third-party dependencies
  • Can handle complex business logic

Cons:

  • Monthly hosting costs ($5-20/month minimum for a VPS)
  • Server maintenance, security patches, uptime monitoring
  • You're running a server to handle what is essentially a form, which defeats the purpose of choosing a static site
  • Overkill for most contact forms

The bottom line

For a standard contact form on a static site, a form backend service is the right choice. You get spam protection, email notifications, and a submission dashboard without writing or maintaining any backend code. If you need custom processing logic (like writing to a specific database or triggering complex workflows), a serverless function gives you that flexibility at the cost of more development work.

Step-by-step: adding a contact form with FormWit

1. Create a FormWit account

Sign up for free. No credit card required. You get unlimited forms and 100 submissions per month on the free plan.

2. Create a new form

In the FormWit dashboard, click "New Form" and give it a name (e.g., "Contact Form"). You'll get a unique form endpoint URL that looks like:

https://app.formwit.com/api/s/abc123def456

3. Add the HTML form to your site

Copy this form into any page on your static site. Replace YOUR_FORM_ID with the ID from your dashboard:

<form action="https://app.formwit.com/api/s/YOUR_FORM_ID" method="POST">
  <label for="name">Name</label>
  <input type="text" id="name" name="name" required />

  <label for="email">Email</label>
  <input type="email" id="email" name="email" required />

  <label for="message">Message</label>
  <textarea id="message" name="message" required></textarea>

  <!-- Honeypot spam protection -->
  <input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off" />

  <button type="submit">Send Message</button>
</form>

4. Deploy and test

Push your changes, wait for the build to finish, and submit a test message. You'll see the submission in your FormWit dashboard and receive an email notification within seconds.

Redirect after submission

By default, FormWit shows a generic success page after submission. To redirect visitors to your own thank-you page, add a hidden redirect_to field:

<input type="hidden" name="redirect_to" value="https://yoursite.com/thank-you" />

The visitor submits the form, FormWit processes it, and then redirects the browser to your specified URL. This keeps the user experience on your domain.

Deployment: works everywhere

Because the form is plain HTML with a POST to an external API, it works on every static hosting platform without any special configuration:

  • Netlify - no build plugins needed (this is not Netlify Forms, it's an external endpoint)
  • Vercel - works as-is, no serverless functions required
  • Cloudflare Pages - zero config
  • GitHub Pages - works out of the box
  • AWS S3 + CloudFront - no Lambda needed for the form
  • Firebase Hosting - static files only, no Cloud Functions needed
  • Any CDN or file host - if it serves HTML, the form works

There's nothing to configure on the hosting side. The form submission goes directly from the visitor's browser to the FormWit API. Your CDN never sees the POST request.

Supported static site generators

The form HTML is framework-agnostic. Drop it into any template or component:

  • Astro - paste into any .astro page or component
  • Hugo - add to any template or content page
  • Jekyll - works in Markdown or HTML layouts
  • Next.js - use in static exports or server-rendered pages
  • Gatsby - add to any React component
  • Eleventy (11ty) - works in Nunjucks, Liquid, or plain HTML templates
  • Nuxt - use in Vue components or static pages
  • SvelteKit - add to any Svelte component
  • Webflow - embed with a custom code block
  • Carrd - use an embed element

If your site produces HTML, FormWit works with it.

Common mistakes to avoid

These are the issues developers hit most often when adding forms to static sites:

Forgetting method="POST"

HTML forms default to GET, which appends form data to the URL as query parameters. This exposes the user's message in the URL, fails for longer messages, and won't work with most form backends. Always set method="POST".

Wrong or missing action URL

If you leave out the action attribute, the form submits to the current page URL, which is a static file on a CDN. The result is a 405 error. Double-check that your action points to your FormWit endpoint, including the protocol (https://).

Missing name attributes on inputs

Inputs without a name attribute are not included in the form submission. This is an HTML spec behavior, not a FormWit limitation. Every input field you want to capture must have a name:

<!-- This input's value WILL be submitted -->
<input type="text" name="email" />

<!-- This input's value will NOT be submitted -->
<input type="text" />

Using action="mailto:"

The mailto: action opens the visitor's email client instead of submitting the form data to a server. It doesn't actually send an email from your site. It also exposes your email address to scrapers. Use a proper form backend endpoint instead.

Not testing after deployment

Forms that work in local development can break in production if environment-specific URLs or CORS settings aren't right. Always submit a test message on the live site after deploying. FormWit's endpoint accepts requests from any origin by default, so CORS is not an issue.

Spam protection

Every FormWit form includes built-in spam filtering that blocks known bot patterns automatically. On top of that, you can add a honeypot field for an extra layer of protection:

<input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off" />

This invisible field catches bots that auto-fill every input. Human visitors never see it. FormWit automatically rejects any submission where the honeypot has a value.

For high-traffic forms, you can also enable CAPTCHA verification. See the spam protection guide for details on honeypot, hCaptcha, reCAPTCHA, and Turnstile options.

What you get on the free plan

  • Unlimited forms
  • 100 submissions per month
  • Email notifications for every submission
  • Dashboard to view and search submissions
  • Spam protection (honeypot + automatic filtering)
  • Custom redirect after submission
  • AJAX / fetch support for single-page apps

No credit card required. Create your free account and add a contact form to your static site in minutes.

Choosing a form backend for your static site? See our alternatives comparison to compare Formspree, Netlify Forms, FormSubmit, and more against FormWit.

Related guides: HTML contact form · Serverless form backend · Send form submissions to email · Free contact form options · Spam protection methods · Copy-paste form templates

Frequently asked questions

Why can't static sites process forms?

Static sites are pre-built HTML files served from a CDN. There is no server-side runtime (no PHP, no Node.js) executing code when a visitor loads the page. When someone submits a form, the browser sends a POST request, but there is nothing on the static host to receive and process it. You need an external form backend to handle that POST request.

Which form backend is best for static sites?

For most static sites, a form backend service like FormWit is the simplest option. You get spam protection, email notifications, and a dashboard with zero backend code. If you need custom server-side logic, a serverless function (Lambda, Cloudflare Workers) gives you more control but requires writing and maintaining code.

Does it work on any hosting provider?

Yes. The form submits directly from the visitor's browser to FormWit's API endpoint. Your CDN never sees the POST request. This works on Netlify, Vercel, Cloudflare Pages, GitHub Pages, AWS S3, Firebase Hosting, and any other platform that serves HTML files.

Want to skip the setup?

FormWit gives you a form endpoint in 60 seconds. Free plan, no credit card.

Create Free Form

Need a form fast?

Build one visually with our free HTML form generator — no coding required.

Try the Form Generator →

Add a form to your static site

Add a contact form to your site in 30 seconds. No backend code required.

Try FormWit Free