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 · Framer
Framer's built-in forms send to a single email, gate webhooks behind paid plans, and limit free submissions. Paste a Code Component instead — same canvas drag-and-drop, real backend, 200 free submissions total, dashboard search, and signed webhooks from Pro.

No server, API route, or SDK. Your Framer 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 Framer 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 tsx you already write.
// ContactForm.tsx — paste into Framer's Code Components panel
// Insert the resulting component into any frame on the canvas.
import { useState } from "react";
import { addPropertyControls, ControlType } from "framer";
export default function ContactForm({ accessKey = "YOUR_ACCESS_KEY" }) {
const [status, setStatus] = useState<"idle" | "loading" | "ok" | "err">("idle");
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setStatus("loading");
const formData = new FormData(e.currentTarget);
formData.append("access_key", accessKey);
const res = await fetch("https://splitforms.com/api/submit", {
method: "POST",
body: formData,
});
const data = await res.json();
setStatus(data.success ? "ok" : "err");
if (data.success) e.currentTarget.reset();
}
return (
<form onSubmit={handleSubmit} style={{ display: "grid", gap: 12 }}>
<input name="name" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<textarea name="message" placeholder="Message" required />
<input type="checkbox" name="botcheck" style={{ display: "none" }} tabIndex={-1} />
<button type="submit" disabled={status === "loading"}>
{status === "loading" ? "Sending…" : "Send"}
</button>
{status === "ok" && <p>Thanks!</p>}
{status === "err" && <p>Something went wrong.</p>}
</form>
);
}
addPropertyControls(ContactForm, {
accessKey: { type: ControlType.String, title: "Access Key" },
});How to add it
To add a contact form to a Framer website you need three things: a free splitforms access key, the tsx 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 Framer 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 Framer 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. And with Stripe connected, your forms can take payments too.

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 200 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
Open the Code Components panel in Framer (sidebar → Components → New Code Component). Paste the snippet above. Save. The component appears in the Insert menu — drag it onto any frame. Set the accessKey property in the right panel.
Yes. Framer's published sites are static React + JS, and Code Components run in the browser. The form posts directly to splitforms.com — no Framer-side configuration beyond the Code Component itself.
Use a status state with four values (idle/loading/ok/err) inside the Code Component. Render error messages from the splitforms response. Style them with inline styles since Framer's CSS modules don't apply inside Code Components.
Not directly — Framer's built-in form widget posts to Framer's backend. Replace it with the Code Component to use splitforms. The Code Component renders inside Framer just like a native widget.
Two options. (1) Render an inline success message or set window.location after a successful fetch. (2) For a native form post, configure the absolute thank-you URL in Dashboard → Form settings → Redirect. Submitted redirect fields are ignored.
Yes — both. Framer's preview executes Code Components (so you can test the form in the editor), and the published site embeds them as React components. Splitforms-side, lock the access key to both your *.framer.app domain and your custom domain.
Yes. In the Framer editor use Insert → Embed and choose HTML, then paste a plain splitforms <form> (or a self-contained iframe with the form in its srcdoc). This drops an Embed component onto the canvas wherever the form should live — a contact section, a footer, or a dedicated Contact page. The form posts straight to splitforms with no external scripts, and the hidden honeypot field still stops bots. The Code Component route is better when you want property controls and inline success states; the Embed route needs zero React knowledge.
Framer reads property controls only if addPropertyControls(Component, {...}) is called after the component is exported. If you put it before the export or wrap it in a conditional, the access-key control disappears from the right panel and you can't set the key visually.
Editing the access key in the right panel re-mounts the form mid-edit. If a user is testing the form when you change the key, their status === 'loading' state resets to 'idle' visually but the in-flight fetch still completes. Not a bug in production — only an editor quirk.
Framer's published sites have a default Content Security Policy that allows known integrations. Splitforms isn't on the default allowlist — you may need to add connect-src https://splitforms.com via Framer's Site Settings → Custom Code → Head HTML, inside a <meta http-equiv="Content-Security-Policy" content="…"> tag.
If you use style={{ fontFamily: '...' }} in a Code Component, you have to import the font manually — Framer's site fonts only auto-apply to canvas-built elements. Use font-family: inherit to inherit from the parent frame.
Browser-default focus rings are sometimes hidden by Framer's reset CSS. Add :focus { outline: 2px solid currentColor; outline-offset: 2px; } in your component's styles — accessibility requires a visible focus indicator.
If your contact form Code Component lives inside a Smart Component variant (e.g. a 'Mobile' variant of a header), Framer re-instantiates the entire Code Component when switching variants — losing your useState for status. A user mid-submission who rotates their device sees the form reset to 'idle' while the fetch is still in flight, then a stale success/error notification when the request resolves into a now-unmounted component (React logs a 'state update on unmounted component' warning). Either lift the form out of any Smart Component variant, or persist status to sessionStorage and rehydrate on mount.
Framer's built-in form widget delivers submissions to a single email address (configured per form) with no dashboard for managing submissions, no webhooks below the Pro plan, and no spam filtering beyond Framer's basic bot detection. CMS-driven Framer forms inherit the same constraints. The native flow works for a portfolio's contact form; it falls apart for any setup that needs Slack/Discord notifications, multiple recipients, CSV export, or tagged form-name routing. Replacing it means writing a Code Component — Framer's mechanism for embedding custom React. That's the pattern splitforms uses: a Code Component with the access key as a property control, dropped onto the canvas like a native widget.
Framer publishes sites to its own CDN — there's no Vercel/Netlify config to manage. The form posts cross-origin to splitforms regardless. Framer's published sites have a default Content Security Policy that may block connect-src to splitforms.com on some plans; if submissions silently fail, add <meta http-equiv="Content-Security-Policy" content="connect-src https://splitforms.com"> via Site Settings → Custom Code → Head HTML. Lock the access key to BOTH your *.framer.app preview URL AND your custom domain — Framer serves both with different Origin headers. Framer's preview environment runs Code Components live, so you can test the form before publishing.
Simple pricing
Choose a plan that fits your workflow — from a free form endpoint to full automations, exports, Stripe payments, and higher submission limits.
For side projects and indie devs.
For agencies and growing products.
Pay $59. 3 years sorted.
No credit card required on Free • Cancel anytime