Get your free splitforms access key
Sign up at splitforms.com, verify your email, and copy your access key from the dashboard. No credit card required.
Contact form · Eleventy
11ty's beauty is its simplicity — and a contact form should match. One Nunjucks (or Liquid) include, one form tag, no serverless function in sight. Pull the access key from global data, render zero JavaScript, and ship submissions straight to your inbox.

No server, API route, or SDK. Your Eleventy form posts straight to one endpoint.
Every submission is emailed to you and saved to a searchable dashboard — spam filtered before it reaches you.
It's your own Eleventy markup and styles. Splitforms is only the backend, so nothing constrains how the form looks.
Copy-paste ready
Replace YOUR_ACCESS_KEY with the key from your dashboard — that's the whole integration. No SDK to install, no build step, just the html you already write.
{#
src/_includes/partials/contact-form.njk
Use in any template with: {% include "partials/contact-form.njk" %}
Set ACCESS_KEY in .env and expose it via eleventy.config.js (addGlobalData)
#}
<form action="https://splitforms.com/api/submit" method="POST">
<input type="hidden" name="access_key" value="{{ splitformsKey }}" />
<input type="text" name="name" placeholder="Name" required />
<input type="email" name="email" placeholder="Email" required />
<textarea name="message" placeholder="Message" required></textarea>
<input type="checkbox" name="botcheck" style="display:none" tabindex="-1" />
<button type="submit">Send</button>
</form>How to add it
To add a contact form to a Eleventy website you need three things: a free splitforms access key, the html snippet above, and your key pasted into it. No backend, server, or SDK — the form posts to one URL and every submission lands in your inbox and dashboard.
Sign up at splitforms.com, verify your email, and copy your access key from the dashboard. No credit card required.
Copy the Eleventy code example into your project and replace YOUR_ACCESS_KEY with the key from step 1.
Submissions arrive in the splitforms dashboard within seconds. Free includes owner email notification attempts; Pro adds Slack, Discord, Sheets, or any signed webhook URL.
Where submissions go
Every submission is emailed to you and saved to a searchable dashboard — spam filtered before it ever reaches you. Search, export to CSV, or forward it to a webhook or Slack on Pro.

No backend needed
Your Eleventy form posts standard FormData to one URL. Splitforms validates the access key, runs its spam checks, and forwards it to your email — so there's no server, API route, or database for you to build or maintain.

Best practices
The difference between a form that works in the demo and one that survives launch traffic — the production-tested defaults, in priority order.

How SplitForms works
splitforms receives the submission, filters spam, saves it to your dashboard and emails you — then, on paid plans, sends it on to your webhooks and integrations. No backend infrastructure to build.

Point your form to your unique SplitForms endpoint. That's it.

We instantly capture and organize every submission in your inbox.

Send data to email, spreadsheets, CRMs, webhooks, and 7,000+ apps.

No credit card required. Set up in under 60 seconds.
Connect & automate
On paid plans, submissions can also go to Slack, Discord, Google Sheets, Notion, Airtable, Zapier or any signed webhook — and splitforms works on the platforms you build on, from WordPress and Shopify to Next.js. With Stripe connected, your forms can take payments too.

Questions
Save the snippet as src/_includes/partials/contact-form.njk. Add splitformsKey to your global data (in _data/site.js, reading from process.env.SPLITFORMS_KEY). Then {% include "partials/contact-form.njk" %} from any template.
Yes — both. The form template is plain HTML with Nunjucks/Liquid syntax that hasn't changed across versions. The only v3 gotcha is that your config file must be ESM (.mjs).
Eleventy is static — it can't render dynamic error responses. Two options: (1) use the pure-HTML form and let splitforms render its default error page (configurable in dashboard), or (2) add a small inline <script> that intercepts submit and renders inline errors (see the AJAX page).
Yes. The snippet is in Nunjucks but the same logic in Liquid is one-line different: {% include 'partials/contact-form.liquid' %} and use {{ splitformsKey }} directly (Liquid doesn't need the URL filter). Save the file with .liquid extension.
Build a /thanks Markdown file with your normal layout, then either add a hidden redirect field to the template pointing at its URL (works on every plan, and wins over the dashboard setting), or set a default absolute URL in Dashboard → Form settings → Redirect.
Yes. The form posts to splitforms.com directly from the static HTML, so it works regardless of whether the page itself was built statically or by Netlify's on-demand builders. No Netlify Function code required.
If you upgraded to Eleventy 3 and your .eleventy.js (CommonJS) silently stopped exposing globals, that's why. Rename to eleventy.config.mjs and use ESM export default. Otherwise addGlobalData('splitformsKey', …) won't reach your templates.
Build the thank-you page as normal Eleventy content, then either add a hidden redirect field to the Nunjucks or Liquid template pointing at its URL (works on every plan, and wins over the dashboard setting), or configure a default absolute URL in Dashboard → Form settings → Redirect.
If you put your access key in _data/site.json (the obvious place), it ships to your repo. Use _data/site.js and read from process.env.SPLITFORMS_KEY instead — then add .env to gitignore. Eleventy auto-loads .env if you have dotenv installed.
If the thank-you page has permalink: false, it is not built and the URL configured in the splitforms dashboard points at a 404. Ensure both the form and thank-you pages have valid permalinks.
If you reuse the variable name splitformsKey inside a paginated template's data, Eleventy's data cascade has paginated data win over global data. Use a unique-enough name like siteSplitformsKey to avoid the conflict.
If you use eleventy-plugin-serverless to render the contact page on-demand via Netlify Functions, you might assume process.env.SPLITFORMS_KEY is read per-request. It isn't — Eleventy serverless bundles the rendered template into a Netlify Function during build, capturing the env vars from your build environment. Rotating the key in Netlify's dashboard does nothing until the next deploy. Fix: read the key inside the form template via <%= process.env.SPLITFORMS_KEY %> rendered at request time using a Nunjucks {% raw %} escape, or skip serverless rendering for the contact page.
Eleventy is a Node-based static site generator — it produces HTML at build time and ships nothing else. There is no runtime, no /api/contact endpoint, no hooks for handling a form POST. The historical workarounds: (a) deploy to Netlify and use Netlify Forms, (b) write a Cloudflare Worker that handles POST /contact and forwards to your email provider (~4 hours plus ongoing operation), or (c) use a third-party form API (Formspree, Web3Forms, Basin, splitforms). Eleventy's data cascade lets you neatly pull an access key from _data/site.js and use it in a Nunjucks/Liquid include — but the actual delivery layer is always external. Splitforms is the lowest-friction external option.
Eleventy deploys to any static host. The form posts cross-origin to splitforms.com so the host is irrelevant for delivery. Eleventy v3's ESM-only config is the major upgrade gotcha — .eleventy.js (CommonJS) silently stops exposing globals; rename to eleventy.config.mjs. Local dev runs on localhost:8080 — add to splitforms allowed-domains for testing or use a separate dev key. _data/site.js (not .json) lets you read from process.env; keep .env in gitignore. For 11ty + Netlify (the classic combo), Netlify Forms is free and unlimited on current credit plans; splitforms is useful when the endpoint must work on every host.
Simple pricing
Free gives you 500 submissions for $0 — no card, no time limit. Pro is $5/month for 5,000 submissions a month, and Annual is $49/year for 15,000 a month with every Pro feature.
For side projects and indie devs.
Every paid feature, for agencies and growing products.
Every Pro feature with triple the volume — $0.27 per 1,000 at full use.
No credit card required on Free • Cancel anytime • Full pricing and FAQ