splitforms.com
All articles/ TUTORIALS10 MIN READPublished June 21, 2026

How to Add a Working Contact Form to Your Lovable App (2026)

Lovable builds the form UI but nothing happens on submit. Wire a real backend in 2 minutes — no Supabase, no Resend, no edge function. Dashboard and spam filtering included on Free; Starter adds email and webhooks.

✶ 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 your Lovable form looks done but isn't

Lovable is an AI app builder: you describe an app, it generates a working React front end with Tailwind styling. It's genuinely good at the part you can see. The trap is the part you can't see. When Lovable generates a "contact form," it produces the markup, the inputs, the validation, and a submit button — but there is no server on the other end of that button. Hit submit on a freshly generated Lovable contact form and, by default, one of three things happens: nothing, a console log, or a fake success toast that never sends anything anywhere.

This is the single most common "my Lovable app is broken" moment, and it isn't a bug. A form is a front-end element; receiving a form submission requires a backend that accepts an HTTP POST, stores it, and notifies you. Lovable knows this, which is why its own guidance points you at connecting Supabase for storage and Resend for email, glued together with an edge function.

That works. It's also a lot of machinery for "email me when someone fills out my contact form." You end up creating a database table you'll never query, writing and deploying an edge function, signing up for a second service (Resend), configuring an API key, and debugging CORS and cold starts — all to move three fields from a form into your inbox. There's a shorter path.

Supabase + Resend vs a hosted form backend

Here's the honest comparison so you can pick deliberately rather than by default.

What you need to doSupabase + Resendsplitforms
Create a database tableYes — schema, columns, RLS policyNo
Write + deploy an edge functionYes — and redeploy on every changeNo
Sign up for an email providerYes — Resend account + API key + domain verifyNo — email included
Spam protectionBuild it yourselfHoneypot + AI classifier, included
Dashboard to read submissionsQuery the table or build a UIBuilt-in, searchable
Lines of app codeDozens, across several filesOne endpoint URL

The rule of thumb: keep Supabase for things that are genuinely your app's data — user accounts, records your product reads and writes. Use a form backend for the thing that is just "a form went off, tell me about it." A contact form, a waitlist, a lead-capture form, a demo request — these don't need to live in your app database, and putting them there is busywork.

Step 1: Get a free splitforms access key (1 minute)

splitforms is the form backend we'll point your Lovable app at. The free tier is 500 submissions/month with AI spam filtering and dashboard capture; Starter adds email forwarding and webhooks — no credit card for Free.

  1. Go to splitforms.com/login
  2. Enter your email and paste the 6-digit code
  3. Copy the access key the dashboard generates (it looks like sf_live_a1b2c3d4...)
  4. Set your notification email under Settings → Notifications — that's where submissions get forwarded

The access key is a public identifier, not a secret. It will live in your Lovable app's client code, which is fine and expected — abuse is handled server-side with rate limiting, Allowed Domains, and spam classification. If you're comparing options first, the free form backend comparison covers the field; splitforms has the largest free tier in it.

Step 2: Tell Lovable to use the endpoint (the easy way)

The fastest path is to let Lovable rewire its own form. Paste this prompt into Lovable's chat, swapping in your access key:

Change the contact form so that on submit it sends the form data
as a POST request to https://splitforms.com/api/submit using fetch.
Include a hidden field "access_key" with the value "YOUR_ACCESS_KEY".
Send the remaining fields (name, email, message) as form data.
On a successful response, show the existing success state and
navigate to /thanks. On error, show an inline error message.
Do not change the visual design or styling of the form.

Lovable will rewrite the submit handler and keep your design intact. This is the whole integration — no table, no edge function, no second service. If you'd rather wire it by hand (or want to understand exactly what Lovable generates), the next section has the code.

Step 3 (manual): The exact submit handler

If you prefer to edit the code yourself, here's a clean React submit handler that posts to splitforms. It works in any Lovable-generated React app and doesn't care how the inputs are styled.

import { useState } from "react";

const ACCESS_KEY = "YOUR_ACCESS_KEY"; // public identifier, safe in client code

export function ContactForm() {
  const [status, setStatus] = useState<"idle" | "sending" | "ok" | "error">("idle");

  async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setStatus("sending");

    const form = e.currentTarget;
    const data = new FormData(form);
    data.append("access_key", ACCESS_KEY);

    try {
      const res = await fetch("https://splitforms.com/api/submit", {
        method: "POST",
        body: data,
      });
      if (!res.ok) throw new Error("Request failed");
      setStatus("ok");
      form.reset();
      // navigate to a thank-you route if you have one:
      // navigate("/thanks");
    } catch {
      setStatus("error");
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      {/* keep all of Lovable's generated inputs and classes exactly as-is */}
      <input name="name" type="text" required />
      <input name="email" type="email" required />
      <textarea name="message" required />

      {/* honeypot: hidden from humans, bots fill it */}
      <input name="botcheck" type="checkbox" tabIndex={-1}
             autoComplete="off" style={{ display: "none" }} />

      <button type="submit" disabled={status === "sending"}>
        {status === "sending" ? "Sending..." : "Send message"}
      </button>

      {status === "ok" && <p>Thanks — we&apos;ll be in touch shortly.</p>}
      {status === "error" && <p>Something went wrong. Please try again.</p>}
    </form>
  );
}

Three things to keep: the access_key appended to the FormData, the name attributes on each input (these become the field labels in your dashboard and Starter notification emails), and the hidden botcheck honeypot. Everything else is yours — keep Lovable's exact markup and Tailwind classes so the design is untouched.

The name attributes are flexible. Rename them to company, budget, project_type — whatever your form collects. splitforms preserves whatever keys you send, so the same handler works for a contact form, a quote request, a waitlist, or a demo request. For a deeper dive on the fetch-and-FormData pattern, see send form data to email with JavaScript fetch.

Step 4: Test and publish

Use Lovable's preview to submit a real test entry. Within about 5 seconds you should see two things:

  1. A notification email in the inbox you set under Settings → Notifications
  2. The submission in your splitforms dashboard, with all fields captured

If both land, publish your Lovable app as normal. One detail worth setting before you ship widely: open the splitforms security tab and add your published Lovable domain (and any custom domain) to Allowed Domains. That ensures only your app can use the key, and it's the right time to do it — once, before launch.

If the submission doesn't arrive, check the dashboard first. If it's in the dashboard but no email came, the issue is forwarding (check spam, verify the notification address). If it's not in the dashboard at all, the POST never reached splitforms — open the browser console and confirm the fetch URL and that the access_key is present. The full checklist is in contact form not working.

Step 5 (optional): Fan out to Slack, Notion, or Sheets

This is where the hosted-backend approach pays off versus Supabase + Resend. Every submission can be delivered to email plus any number of signed webhooks in parallel, configured in the dashboard — not in your Lovable app. So adding a Slack alert or a Notion row later doesn't mean regenerating or redeploying the app.

If you're building with AI tooling more broadly, splitforms also ships an MCP server — so an agent in Cursor or Claude can read submissions and configure forms through a typed protocol, not a scraped dashboard. That's the part generic "works with AI builders" backends can't match.

What to do next

FAQ

Why doesn't my Lovable contact form do anything when I submit it?

Because Lovable generates the front end — the React, the Tailwind, the validation — but it doesn't stand up a server to receive the POST. By default a generated form either does nothing on submit or logs to the console. To actually capture submissions you need a backend: either Supabase + an email service like Resend wired through an edge function, or a hosted form backend you point the form at. The hosted route is one line of code; the Supabase + Resend route is several files and two dashboards.

Do I need Supabase and Resend to collect form submissions in Lovable?

No. That's Lovable's default recommendation, but it's three moving parts (a database table, an edge function, and an email provider) for what is fundamentally 'receive a POST and email it to me.' A hosted form backend collapses all of it into a single endpoint URL. You keep Supabase for the parts that actually need a database — auth, app data — and let the form backend handle form delivery, spam filtering, and notifications. Fewer parts, fewer things to break.

Will telling Lovable to use a custom endpoint break the generated design?

No. You're only changing where the form sends data, not how it looks. Keep Lovable's generated markup and styling exactly as-is and change the submit handler to POST to the splitforms endpoint. The visual design, the Tailwind classes, the layout — all untouched. You can even paste the prompt in this guide directly into Lovable's chat and it will rewire the handler for you.

Is the access key safe to expose in a Lovable app's client code?

Yes. The splitforms access key is a public identifier, not a secret — it's designed to live in client-side code where anyone can view-source it. Abuse is prevented server-side with rate limiting, the Allowed Domains setting in the security tab, and an AI spam classifier. If a key ever gets abused, rotate it from the dashboard in one click and redeploy. This is the same model Formspree, Web3Forms, and every client-side form backend use.

Can I still send submissions to Slack, Discord, or Notion from Lovable?

Yes. Once the form posts to splitforms, every submission can fan out to email plus any number of signed webhooks in parallel — Slack, Discord, Notion, Google Sheets, Zapier, or your own server. You wire those destinations once in the splitforms dashboard, not in your Lovable app, so adding a new destination later doesn't require regenerating or redeploying the app.

Does this work with Lovable apps that are connected to Supabase already?

Yes. The two don't conflict. Keep Supabase for auth and app data; route the contact form to splitforms. You can even store a copy of each submission in Supabase via a splitforms webhook if you want everything in one database — but for a contact or lead form, most teams just let splitforms own it and skip the table entirely.

How do I redirect to a thank-you page after the Lovable form submits?

If you submit via fetch (the AJAX approach in this guide), handle the success response in JavaScript and navigate with your router — for a Lovable React app that's usually a React Router or Next navigation call to a /thanks route. If you use a plain HTML form post instead, add a hidden input named redirect with your thank-you URL and splitforms will 302 the browser there automatically.

About the author
✻ ✻ ✻

Get your free contact form API key in 60 seconds.

500 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 dashboard. Starter adds inbox delivery.

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