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 · Svelte
SvelteKit, classic Svelte, Vite, Astro islands — pick your flavor. One reactive component, full form handling, no backend route. Works with Svelte 4 stores and Svelte 5 runes.

No server, API route, or SDK. Your Svelte 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 Svelte 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 svelte you already write.
<script>
let status = "idle";
async function onSubmit(e) {
status = "loading";
const formData = new FormData(e.target);
formData.append("access_key", "YOUR_ACCESS_KEY");
const res = await fetch("https://splitforms.com/api/submit", {
method: "POST",
body: formData,
});
const data = await res.json();
status = data.success ? "ok" : "err";
if (data.success) e.target.reset();
}
</script>
<form on:submit|preventDefault={onSubmit}>
<input name="name" required />
<input name="email" type="email" required />
<textarea name="message" required />
<input type="checkbox" name="botcheck" style="display:none" tabindex="-1" />
<button disabled={status === "loading"}>
{status === "loading" ? "Sending…" : "Send"}
</button>
{#if status === "ok"}<p>Thanks!</p>{/if}
{#if status === "err"}<p>Error.</p>{/if}
</form>How to add it
To add a contact form to a Svelte website you need three things: a free splitforms access key, the svelte 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 Svelte 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 inbox delivery; 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 Svelte form posts standard FormData to one URL. Splitforms validates the access key, runs the spam classifier, 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
Connect your form, collect every submission, and send data where it needs to go — without building backend infrastructure.

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
SplitForms works with the destinations you route to and the platforms you build on — from Slack and Sheets to WordPress, Shopify, and Next.js.

Trusted by indie teams and agencies shipping forms worldwide
Testimonials
40 quotes on record — from indie hacks to agency migrations.
“I replaced a Lambda + DynamoDB + SES contact form with six lines of HTML. It took eleven minutes, and the dashboard is better than what I was going to build.”
“We migrated 14 client sites off Formspree in a single weekend. The price is a third of what we paid, the API is more honest, and the spam filter actually works.”
“The webhook payload is signed, idempotent, and well-shaped. It reads like code from a competent team, not a CRUD app held together with duct tape.”
“I stopped reaching for Typeform on small marketing sites. splitforms covers 90% of the use case at none of the bloat.”
“I onboarded our whole agency in an afternoon. The MCP integration meant Cursor literally dropped the form straight into our client repos for us.”
“The free plan gave me 500 submissions before I paid a cent, and Pro is five dollars a month. I've spent more on coffee deciding which backend to use.”
“Spam went from forty junk entries a day to zero, with no reCAPTCHA puzzle ruining the form. The honeypot and time-trap just quietly do their job.”
“Point the form action at one endpoint and you're done. No SDK, no client library, no build step. This is how a form backend should feel.”
“Leads land in Slack the second someone submits, and a copy goes to Google Sheets for the sales team. I wired both up in under ten minutes.”
“I run a static Hugo site on a five-dollar VPS. splitforms gave it a real contact form without me standing up a single server.”
Questions
Paste the .svelte snippet above into any component file (e.g. src/lib/ContactForm.svelte), import it where you need it, and replace YOUR_ACCESS_KEY. That's it.
Yes — both. The component is client-only because it uses fetch, but it hydrates inside an SSR-rendered page without issue. For server-side submission with progressive enhancement, see the dedicated /forms/sveltekit page.
Use a status variable with four states: idle, loading, ok, err. Show inline messages with {#if} blocks. The fetch returns { success, message? } — render data.message for the user when success is false.
Yes — that's the SvelteKit-specific pattern (server-side, progressive enhancement, no client JS required). It's documented on the /forms/sveltekit page.
Two options. Stay on-page with a Svelte-rendered success message (default in our snippet), or configure a thank-you URL in Dashboard → Form settings → Redirect and use a native form submit.
Yes. The hero snippet uses Svelte 4 syntax (works in 5 too with a deprecation warning); the alternative-pattern snippet uses Svelte 5 runes. Pick whichever matches your project.
Svelte 5 introduces $state(...) runes; Svelte 4 uses plain let status = 'idle'. They're not interchangeable in the same component. Check package.json for "svelte": "^5" and use runes accordingly. Mixing them throws a confusing 'rune used outside .svelte.js' error.
If you copy a Svelte 4 snippet into a Svelte 5 project, the on:submit|preventDefault modifier syntax is gone. Use onsubmit={(e) => { e.preventDefault(); … }} or migrate to a SvelteKit form action that handles preventDefault for you.
FormData reads from name="…" attributes, not Svelte's bind:value. If you bind a value but skip the name attribute, the field is silently dropped from the POST body. Always set both.
$env/static/private is a SvelteKit feature, not a Vite-Svelte one. In a vanilla Vite + Svelte project, use import.meta.env.VITE_SPLITFORMS_KEY (must have the VITE_ prefix or it's undefined client-side).
During development, saving a .svelte file may re-mount the component mid-submission. The fetch keeps running but the UI loses its 'loading' state. Not a real bug — just don't panic when you see it in dev. Production behaves correctly.
If you write $: if (status === 'ok') resetForm(); and status = 'ok' inside an async fetch handler, the block runs synchronously after each top-level update — but resetForm() may execute before the DOM has flushed the disabled state on the submit button, causing a visible flicker where the button briefly re-enables and then the form clears. Either move the reset inside the handler after await tick(), or use Svelte 5's $effect rune which schedules properly relative to renders. Svelte 4's $: is synchronous and easy to misuse for side effects.
Plain Svelte (without SvelteKit) is a compiler — there's no runtime route handler, no server, no built-in form delivery. To ship a working form natively you'd add a separate Node/Bun/Express layer, write the SMTP wiring, and operate it. SvelteKit ships form actions and use:enhance for progressive enhancement, but those just give you ergonomic ways to call your own backend; the actual email-delivery, spam-filtering, and submission-storage are still on you. Svelte 5 runes change reactivity syntax, not the operational model. Splitforms removes the entire 'add a backend' step: the runtime is one URL, hosted by us.
Vite + Svelte (non-Kit) builds a static bundle for any host. SvelteKit deploys via adapters: @sveltejs/adapter-vercel, -netlify, -cloudflare, -node, -static. The form posts client-side regardless of adapter, so the form itself works identically on each. Use VITE_SPLITFORMS_KEY for plain Vite-Svelte projects; SvelteKit uses $env/static/public from PUBLIC_SPLITFORMS_KEY. Svelte islands embedded in Astro hydrate via client:visible — the form's fetch only runs after the user scrolls to it, saving JS execution on initial load. Lock the access key to your domain.
Simple pricing
Choose a plan that fits your workflow — from a free form endpoint to full automations, exports, and higher submission limits.
Free forever
For side projects and indie devs.
For agencies and growing products.
Pay $59. 3 years sorted.
No credit card required on Free • Cancel anytime