splitforms.com
All articles/ GUIDES8 MIN READPublished May 15, 2026

Working Contact Forms for Jamstack Sites (2026)

How to add a contact form to a Jamstack site (Next.js, Astro, Hugo, Eleventy, Gatsby) without an API route, server, or SMTP setup — using splitforms as the backend.

✶ Written by
splitforms.com / blog

Founder of splitforms — the form backend API for developers. Writes about form UX, anti-spam, and shipping web apps without backend code.

Why Jamstack contact forms are hard

The Jamstack model — pre-built static HTML on a CDN — eliminates most of the operational pain of running a website. No server to patch, no database to back up, no PHP runtime to upgrade. It also eliminates the place where a contact form historically lived. A form needs somethingto receive the POST, validate the fields, send an email, and store the submission. On a static-only stack, that something doesn't exist by default.

Three patterns have emerged to bridge the gap:

  1. Serverless functions. Add a /api/contact endpoint via Netlify Functions, Vercel Functions, or Cloudflare Workers. You write the handler, manage SMTP credentials, build the spam filter, persist submissions yourself. Highest control, most maintenance.
  2. Host-built-in form handlers. Netlify Forms is the only widely-used one. Free tier is 100 submissions/month, tied to Netlify hosting, with limited spam tooling and no submission re-delivery.
  3. Hosted form backend. Point the form action at a service that receives the POST, emails you, stores the submission, and fires webhooks. splitforms is one such service — free for 1,000 submissions/month, no credit card.

This post walks through option 3 because it stays purely static and works on every Jamstack stack and every host. The other two are worth considering when you have specific reasons (existing serverless infrastructure, regulatory hosting requirements).

The pattern in one HTML snippet

<form action="https://splitforms.com/api/submit" method="POST">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
  <input type="hidden" name="redirect"   value="https://yoursite.com/thanks" />

  <label>Name<input name="name" required /></label>
  <label>Email<input name="email" type="email" required /></label>
  <label>Message<textarea name="message" required></textarea></label>

  <!-- Honeypot. splitforms recognizes the field name as a spam trap. -->
  <input type="checkbox" name="botcheck" style="display:none" tabindex="-1" />

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

That's the complete integration. No JavaScript required. The form POSTs natively; splitforms accepts the submission, sends the email, stores the row, fires webhooks, and 302s the visitor to the redirect URL. The page is fully static; the only network call on submit goes to splitforms.com.

Per-framework gotchas

Next.js

On a Next.js page using the App Router and static export (output: 'export'), the form above lives inside any server component. No "use client" directive needed — the form is a plain HTML element. If you want AJAX submission for inline success states, move the form into a client component and intercept submit with fetch. See the Next.js guide for both patterns.

Astro

Astro components are static by default. Drop the form HTML into any .astro file under src/pages/ or as a shared component in src/components/. No client island, no JS framework, no SSR adapter. Astro Actions are an alternative but require enabling an SSR adapter — see the dedicated Astro guide for the comparison.

Hugo

Hugo's template engine handles the form like any other HTML. Save the snippet in a partial (layouts/partials/contact-form.html) and include it on the contact page. Store the access key in config.toml under params.splitforms_key so you can change it without editing markup. Full pattern at /forms/hugo.

Eleventy / Jekyll / Gatsby

All three follow the same pattern: drop the HTML into a layout or template file, reference the access key from config, deploy. Eleventy reads from _data/site.json, Jekyll from _config.yml, Gatsby from gatsby-config.js. The form HTML is unchanged across them.

Host compatibility

The action-URL pattern works on every static host because all you need is for the host to serve HTML. Verified working:

  • Netlify static (bypasses Netlify Forms entirely)
  • Vercel static + Vercel with SSR
  • Cloudflare Pages
  • GitHub Pages
  • AWS S3 + CloudFront
  • Render static sites
  • Surge.sh
  • Self-hosted Nginx / Apache

The only operational requirement is HTTPS (the form POSTs to https://splitforms.com and modern browsers block mixed-content POSTs from HTTP pages). Every modern static host ships HTTPS by default.

Spam handling without a server

On a Jamstack site you have no middleware to run anti-spam logic. splitforms handles this server-side: every submission goes through an AI spam classifier on top of honeypot detection. Recognized spam routes to a separate folder in your dashboard; legitimate submissions arrive in your inbox.

The honeypot is just one hidden <input> with a name splitforms recognizes (botcheck, _gotcha, hp, website, and a handful of others). Bots fill every input they find; real users don't see the hidden one; submissions where the honeypot is non-empty get classified as spam. See the spam-bot guide for the full pattern.

Wiring submissions to Slack, Discord, CRMs

Once the form is live, configure webhooks in the splitforms dashboard to forward submissions wherever you want. The submission payload is JSON; common destinations:

FAQ

Why is it hard to add a contact form to a Jamstack site?
Jamstack sites are pre-built static HTML hosted on a CDN (Netlify, Vercel, Cloudflare Pages, S3). They have no server runtime to receive form POSTs and email you, which is the historical job of PHP mail() or a Node.js endpoint. You have three options: (1) add serverless functions (more infra to maintain), (2) use a built-in form handler from the host (Netlify Forms is the only popular one, with strict free-tier limits), or (3) point the form action at a hosted form backend like splitforms. Option 3 stays purely static and works on any host.
Does splitforms work with every Jamstack framework?
Yes — Next.js (static export or SSR), Astro, Hugo, Eleventy, Gatsby, Jekyll, Nuxt static, SvelteKit static, Hexo, Zola, and anything else that emits HTML files. The form is just <form action=splitforms.com/api/submit method=POST>, which is part of HTML, not the framework. Framework-specific guides live at /forms/<platform>.
Will my Jamstack site need server-side rendering after adding a contact form?
No. The static-action-attribute pattern works on a fully pre-rendered HTML page — no SSR, no API route, no Node adapter. You can deploy the same static output to Cloudflare Pages, S3, or GitHub Pages and the form still works. SSR is only needed if you want to proxy the POST server-side, which is rare and adds latency without security benefit (the access key is rate-limited and origin-locked anyway).
Can I use Netlify Forms instead of splitforms on a Netlify site?
Yes, but the trade-offs are worth knowing. Netlify Forms has a 100-submission/month free cap (vs splitforms's 1,000), is tied to Netlify hosting (lock-in), and the spam dashboard is thin. splitforms works on Netlify the same way it works anywhere — point your action attribute at splitforms.com/api/submit and the form bypasses Netlify Forms entirely.
How do I handle the success state without a page reload?
Two options. (1) Native form submission: splitforms 302s to a 'redirect' URL you specify in a hidden field — your thank-you page loads, no JS required. (2) AJAX submission: intercept the submit event with JavaScript, POST via fetch, update the DOM inline. The /guides/submit-form-with-ajax guide has a 15-line vanilla JS version that works in every Jamstack framework.
What about spam — Jamstack sites don't run anti-spam middleware.
splitforms handles spam server-side. Every submission runs through an AI classifier on top of honeypot detection. Spam goes to a separate folder in the dashboard; legitimate submissions reach your inbox. No reCAPTCHA, no third-party JS on your page.
About the author
✻ ✻ ✻

Get your free contact form API key in 60 seconds.

1,000 free form submissions per month. No credit card. No SDK, no PHP, no plugin. Drop one POST endpoint in your form and submissions land in your inbox.

Generate access key →Read the docs
v0.1 · founders pricing locked in · early access open