A Framer contact form that actually sends emails (in four minutes)

April 4, 2026 · 5 min read

Designer at a laptop setting up a Framer contact form

Framer is the tool I reach for when I want a landing page to look good in three hours instead of three days. The one thing that always trips people up is forms. Framer has a form element. The default delivery is… fine. You get an email from Framer's system, it lands in your inbox, life goes on.

Then you want Slack. Or Notion. Or a CRM. Or you want retries when your webhook endpoint blips. That's when you need to point the form somewhere else.

Here's the short version, stopwatch style.

Step 1 — Get a form URL

Sign up for a hosted form backend. I'll use FormTo. After you create a form, you get a URL like:

https://api.formto.dev/f/your-form-slug

Copy it somewhere safe. One minute down.

Step 2 — Drop the Framer form onto your canvas

Open your Framer project. Drag a Form component onto the page. Add the fields you want — name, email, message. Make the labels friendly. This is what Framer is genuinely great at, so lean into it.

While you're there:

  • Add a text input, call it website, set its visibility to hidden (or position it off-screen with opacity: 0 and pointer-events: none). This is your honeypot. Do not delete it. Real humans will never find it; bots will fill it and get dropped server-side.
  • Turn off Framer's default "show success message" if you want a proper thank-you page instead.

Step 3 — Point the form at your endpoint

In the Form component's settings panel, look for the "Action URL" or "Submit to" option. Paste your form URL there. Method: POST. Encoding: application/x-www-form-urlencoded (the default). Save.

That's the whole wiring. The form now submits to your backend instead of Framer's default.

If your Framer version doesn't expose the action URL directly, you can drop a plain HTML form in a Code component:

export default function ContactForm() {
  return (
    <form
      method="POST"
      action="https://api.formto.dev/f/your-form-slug"
      style={{ display: 'flex', flexDirection: 'column', gap: 12 }}
    >
      <input name="name" placeholder="Your name" required />
      <input name="email" type="email" placeholder="Email" required />
      <textarea name="message" placeholder="Message" required />

      <input
        name="website"
        tabIndex={-1}
        autoComplete="off"
        style={{ position: 'absolute', left: '-9999px' }}
        aria-hidden="true"
      />

      <input type="hidden" name="_redirect" value="https://yoursite.com/thanks" />

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

Both approaches work. The Form component is prettier out of the box. The Code component gives you full control when you want it.

Step 4 — Wire up the notifications

Back in the FormTo (or whichever backend) dashboard:

  • Add your email under notifications. Real submissions will arrive formatted, not as raw JSON.
  • Optional: paste a Slack incoming webhook URL into the webhook field. Every submission pings a channel. Nice for sales channels where "new lead just came in" creates a little dopamine hit that keeps people responsive.
  • Optional: point the same webhook at your CRM or a Zapier/Make workflow. You're the routing layer; the backend handles the hand-off.

Four steps. No Framer plan upgrade. No custom code if you don't want it. Your contact form now sends to email, Slack, and whatever else you wire in.

A word on Framer's built-in form delivery

I don't want to trash it. For the first week of a new landing page, it's exactly enough. The reason to point elsewhere is when you want:

  • Webhook retries when your downstream is briefly unreachable
  • Submission search across thousands of entries
  • Spam filtering that doesn't rely on a CAPTCHA (which makes Framer pages feel slower and gets in the way of conversion)
  • EU data residency, if you need it
  • A dashboard you can give to a client without giving up your whole Framer login

None of those are shortcomings of Framer. They're just different concerns. Framer is a site builder. Form backends are form backends.

The thing I wish someone had told me

Landing pages live or die on the first 48 hours after launch. If your Framer form breaks silently — because you never tested it, because the default notification went to spam, because the "thank you" message never showed — you will lose leads you didn't know you had.

Test the form from a phone, on a different network, before you ship. Fill in the honeypot on purpose and confirm the submission gets dropped. Submit a real one and confirm the email shows up. Five minutes of testing saves a week of wondering why nobody contacts you.


Want to try the exact setup above? Grab a free form slug, paste it into Framer, and test-drive it. Twenty-five submissions a month on the free plan, no card, no trial clock.

Or read the Next.js version if your Framer prototype is about to graduate into a full codebase.

← All posts