splitforms.com
All articles/ TUTORIALS9 MIN READPublished May 11, 2026

How to Add a Contact Form to a Notion-Built Site 2026

Add a working contact form to your Notion-built site (Super, Potion, Feather) in 2026 — paste-in HTML, custom styling, and reliable email delivery.

✶ 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 Notion can't actually do contact forms

Notion is a beautiful editor with no email infrastructure behind it. The product is built to organize pages, databases, and embeds — not to receive HTTP POSTs, deliver mail, or filter spam. So when you publish a Notion page as a site, the "form" you see there is one of three things, none of which are a real backend:

  • A database with a Form view. It writes rows into Notion, but there is no email notification, no webhook, no spam protection, and no domain restriction.
  • A third-party widget pasted as an /embed. It works, but it's an iframe to someone else's service — Tally, Typeform, Google Forms — with their branding and their pricing.
  • A mailto: link. Exposes your address to scrapers, depends on the visitor having a desktop mail client configured, and silently fails on mobile.

The fix is straightforward. Almost everyone shipping a Notion-built site in 2026 is doing it through one of three publishing layers — Super.so, Potion.so, or Feather — and all three let you paste raw HTML into the page or globally. That HTML can be a splitforms form, which gives you email delivery, AI spam filtering, webhooks, and a dashboard, on a free tier that covers most personal sites. The rest of this guide walks through the exact paste-in flow for each builder, plus styling, validation, and the troubleshooting steps for the embed quirks each one has.

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

You need one access key, total, for your whole Notion site. Get it before you open your builder so you can paste it once and forget about it.

  1. Go to splitforms.com/login.
  2. Type your email, paste the 6-digit code, you're in.
  3. The dashboard shows your access key under the first form. Copy it — it's a 24+ character string.
  4. Under Settings → Allowed Domains, add the domain you'll publish to (e.g. yourdomain.com) so nobody else can hit your endpoint with the key.

No credit card, no plan picker, no "7-day trial that turns into a charge." The free tier is 1,000 submissions a month and it stays free unless you upgrade. If you're comparing this against other backends first, read best free form backend services 2026 — splitforms tops it on free-tier headroom and webhooks.

Step 2: Build the HTML form (once, reusable)

This is the form you'll paste into whichever Notion builder you use. Keep it minimal — Notion sites read best with restraint. Two text inputs, a textarea, a submit button, a hidden honeypot.

<form action="https://splitforms.com/api/submit" method="POST" class="sf-form">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
  <input type="hidden" name="redirect"   value="https://yourdomain.com/thanks" />

  <label>
    Name
    <input type="text" name="name" required />
  </label>

  <label>
    Email
    <input type="email" name="email" required />
  </label>

  <label>
    Message
    <textarea name="message" rows="5" required></textarea>
  </label>

  <!-- Honeypot: real users never see this; bots fill it and get blocked -->
  <input type="checkbox" name="botcheck" style="display:none" tabindex="-1" autocomplete="off" />

  <button type="submit">Send message</button>
</form>

Two notes before you paste this anywhere:

  • Replace YOUR_ACCESS_KEY with the string you copied in step 1.
  • Replace the redirect URL with a real page on your Notion site (a /thanks page works — see step 6). If you skip redirect, splitforms shows its own neutral success page, which is fine but off-brand.

That's the entire form contract. Field names are arbitrary — splitforms takes whatever you send and emails it back to you. If you want phone or company fields, add them with name="phone" and name="company". The endpoint doesn't care about schema.

Step 3a: Embed in Super.so

Super.so is the most-used Notion site builder in 2026 and the friendliest for raw HTML. You have two places to paste: Global Code Injection (best for the CSS) and HTML block / Code embed (best for the form itself).

Paste the form into a page

  1. Open your Notion source page (the one Super mirrors). Add a new block: type /embed and pick the embed primitive.
  2. In Super's dashboard, go to your site → Customize → Code Injection → Head for the CSS, and Customize → HTML Embed for the form HTML.
  3. Or simpler: drop a Super HTML block directly on the Notion page using Super's !html syntax (their docs call it HTML blocks). Paste the form code from step 2 inside it.
  4. Hit publish in Super. The form appears on the next deploy, usually within 10 seconds.

Super quirks to know

  • Super wraps the page in its own container; if you paste position: absolute CSS, it will escape the column. Stick with normal flow.
  • Super's preview cache is aggressive. After publishing, hit your live URL in an incognito window — the editor preview can be 30–60 seconds behind.
  • If you want the form on every page footer, paste it in Code Injection → Body End wrapped in a div with a class — then position it with CSS.

Step 3b: Embed in Potion.so

Potion has a similar architecture to Super but the panel names are different. Look for Custom Code under your site settings.

  1. Potion dashboard → your site → Settings → Custom Code.
  2. Paste the CSS block (from step 4 below) into Head.
  3. For the form HTML, Potion supports a Code Block in the Notion source page itself: add a code block, set the language to html, paste the form, then in Potion's page settings enable Render HTML in code blocks.
  4. Save and republish.

Potion quirks to know

  • The "Render HTML in code blocks" toggle is per-page in some Potion plans and global in others. If your form shows up as literal HTML text, you forgot to flip the switch.
  • Potion's default code-block styling has a gray background. Add .notion-code { background: transparent; padding: 0; } to the head CSS so your form sits on a clean canvas.
  • Potion strips <script> tags from code blocks for safety. The plain HTML POST flow in step 2 doesn't need any JavaScript, so this doesn't affect you. If you want AJAX submit, add the script via Custom Code → Head instead.

Step 3c: Embed in Feather

Feather is the "Notion-as-CMS for blogs" builder. It's narrower than Super or Potion — fewer customization knobs — but it still has a Custom Code surface.

  1. Feather dashboard → Settings → Custom Code (sometimes called Site Code depending on plan).
  2. Drop the CSS into Head.
  3. For the form itself, create a Notion page named "Contact" (or whatever you want it called publicly). In Feather's page-level settings, enable Allow HTML embeds, then paste the form into a Notion code block set to html, identical to the Potion flow.
  4. Publish. Feather rebuilds the static page on save.

Feather quirks to know

  • Feather caches at the CDN edge. After republishing, you may need to clear your browser cache or wait 60–90 seconds for the form to appear.
  • Feather's default font stack is more constrained than Super's. Use the CSS variable --sf-font in step 4 to inherit from the theme instead of hard-coding a font-family.
  • Feather doesn't expose a global "Body End" injection slot on the Starter plan. If you need site-wide CSS, the Head slot is fine — body-end is mostly for analytics scripts anyway.

Step 4: Style the form to match Notion's aesthetic

Notion's visual system is restrained: white surfaces, 1px borders in a near-gray, soft 4–8px radii, an Inter / IBM Plex Sans stack, and a single accent color. The CSS below mirrors that. Paste it into your builder's Head injection slot (Super: Code Injection → Head; Potion: Custom Code → Head; Feather: Custom Code → Head).

<style>
  :root {
    --sf-ink: #37352f;
    --sf-ink-2: #6b6a64;
    --sf-line: #e9e9e7;
    --sf-bg: #ffffff;
    --sf-accent: #2383e2; /* Notion blue. Swap for your brand. */
    --sf-font: -apple-system, BlinkMacSystemFont, "Inter", "IBM Plex Sans", "Segoe UI", sans-serif;
  }

  .sf-form {
    max-width: 560px;
    margin: 32px 0;
    display: flex;
    flex-direction: column;
    gap: 14px;
    font-family: var(--sf-font);
    color: var(--sf-ink);
  }

  .sf-form label {
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: 14px;
    font-weight: 500;
    color: var(--sf-ink-2);
  }

  .sf-form input,
  .sf-form textarea {
    width: 100%;
    padding: 10px 12px;
    font-size: 15px;
    font-family: inherit;
    color: var(--sf-ink);
    background: var(--sf-bg);
    border: 1px solid var(--sf-line);
    border-radius: 6px;
    transition: border-color 120ms ease;
  }

  .sf-form input:focus,
  .sf-form textarea:focus {
    outline: none;
    border-color: var(--sf-accent);
  }

  .sf-form button {
    align-self: flex-start;
    padding: 10px 18px;
    font-size: 14px;
    font-weight: 600;
    color: #ffffff;
    background: var(--sf-accent);
    border: 0;
    border-radius: 6px;
    cursor: pointer;
  }

  .sf-form button:hover { filter: brightness(0.95); }
</style>

That CSS is intentionally short. It uses Notion's actual ink color (#37352f), Notion's actual border color (#e9e9e7), and Notion's actual blue accent (#2383e2). Swap the accent to your brand color if your site uses one — every Notion site I've helped ship in the last year keeps these tokens and just changes that single value.

Step 5: Validation, spam protection, and mobile preview

The form in step 2 already has the three things that matter:

  • HTML5 validation via required on every field and type="email" on the email input. The browser blocks submit until the format is right. No JavaScript needed.
  • Honeypot spam protection via the hidden botcheck input. Bots that scrape forms and submit them automatically fill every field they find, including invisible ones. Splitforms drops any submission where botcheck is non-empty. See the deeper breakdown in honeypot vs reCAPTCHA.
  • Server-side AI spam classification on top of the honeypot. You don't configure anything for this — it runs by default on every splitforms submission. Walkthrough: AI form spam detection.

Before you publish, preview on mobile. Notion site builders are good at responsive layout but the CSS above caps the form at 560px and switches to single-column on narrow screens automatically (because of flex-direction: column). Test these three things on a phone:

  1. Tap each input. The native keyboard should open the right type (email keyboard for the email field, default keyboard for name).
  2. The button should have at least 44px tap target height — the padding in step 4 gives you that.
  3. Submit a real test. The redirect should fire and land you on the thank-you page.

Step 6: Build a thank-you page and publish

The redirect hidden input in step 2 sends the visitor somewhere after submit. Create that page in Notion: a single H1 ("Thanks — we'll be in touch"), one paragraph ("Your message just landed in our inbox. Expect a reply within one business day."), and a link back to home. Publish it through your builder and copy the URL into the form's redirect attribute.

Then republish the contact page. Open it in an incognito window so you bypass cache. Submit a real message. Check three things, in order:

  1. The browser redirects to your /thanks page within 1–2 seconds.
  2. An email lands in your inbox (the one you signed up with on splitforms) within 5–10 seconds. Check Spam if you don't see it — first-time delivery sometimes routes there until your address has a reputation.
  3. The splitforms dashboard at splitforms.com/dashboard/submissions shows the row.

If all three pass, you're shipped. The form is now live, spam-protected, and emailing you on every submission. No plugin, no third-party iframe, no monthly add-on on top of your Notion builder bill.

Troubleshooting Notion-builder embed quirks

Most issues come from one of the three builders sandboxing your HTML differently. Here's what to check, in order:

  • Form renders as plain text instead of a form (Potion / Feather). The code block's "Render HTML" toggle is off. Open the page settings in your builder and flip it on.
  • Form is invisible / collapsed to zero height (Super). The parent column has overflow: hidden. Wrap your form in <div style="min-height: 320px"> as a quick fix, or use Super's full-width HTML block instead of an in-column embed.
  • Submit does nothing and the URL doesn't change. Almost always the action attribute is missing or misspelled. Open DevTools, inspect the form, confirm action="https://splitforms.com/api/submit" is present.
  • splitforms returns 401. The access key is wrong, has whitespace, or your Allowed Domains setting doesn't include the published Notion site URL. Recopy the key and check the domain list in the splitforms dashboard.
  • Submissions deliver but the email goes to spam. Your inbox doesn't trust the sender yet. Mark one as "not spam" and add the splitforms notification address to your contacts. For a deeper fix, see why contact form emails go to spam.
  • The form looks fine on desktop but cramped on mobile. Your builder is injecting its own container padding inside the iframe. Add .sf-form { padding: 0 16px; } to the head CSS to add breathing room only on the form's parent.
  • Honeypot is catching real users. A password manager auto-filled the hidden botcheck checkbox. Add autocomplete="off" (already in step 2's snippet) and confirm the field is hidden via display:none, not just visibility:hidden.
  • Notion design-system colors don't match yours. Your builder may have a custom theme overriding the CSS variables. Increase specificity: change .sf-form input to .notion-page .sf-form input or wrap the form in an explicit class and target that.

Next steps and where to read more

FAQ

Can I add a real form directly inside Notion, without a site builder?

Not a real one. Notion's native form-style blocks (databases with form view, third-party widgets via /embed) can capture clicks, but they don't send email, don't run spam protection, and don't expose webhooks. The standard pattern in 2026 is: build the site visually in Notion, publish through Super.so, Potion.so, or Feather, then paste in an HTML form that posts to splitforms. That gives you a real backend without leaving the Notion editing flow.

Which Notion site builder makes embedding a form easiest?

Super.so is the most flexible — it has both a global Code Injection panel and per-page HTML embed blocks, so you can drop a form anywhere and style it once for the whole site. Potion.so works similarly with its Custom Code feature. Feather is built around blogs and newsletter pages, so its embed surface is a little narrower, but raw HTML blocks still work fine. If you don't have a builder yet and only need a contact form, Super is the safest pick.

Will the form's design clash with Notion's clean look?

Only if you paste in default browser styles and walk away. Notion's aesthetic is white background, IBM Plex / Inter style fonts, generous spacing, soft borders, and limited color. The CSS block in this guide matches that: white inputs, 1px light gray borders, 8px radius, system font, and a single accent color. Drop it in, change the accent to your site's brand color, and the form looks like it shipped with the theme rather than an iframe glued on.

Do I need JavaScript for the form to work?

No. The default splitforms flow is a plain HTML POST — the browser submits the form, splitforms responds with a redirect or a thank-you JSON payload, and the visitor lands on a confirmation page. That works in every Notion-published site, even ones with strict embed sandboxes. JavaScript is only needed if you want inline validation, AJAX submit without page reload, or a custom thank-you panel. Both modes are documented in the splitforms /docs.

How do I stop spam without a visible captcha?

Two layers: a hidden honeypot field named botcheck (covered in step 4) and splitforms' AI spam classifier on the server. The honeypot kills 90 percent of bots at zero UX cost — they fill every field they see, including invisible ones, so any submission with botcheck populated is dropped. The AI layer catches the rest by scoring message content. Visible captchas are usually unnecessary for a low-traffic Notion site and they hurt conversion on mobile.

Why does my Notion-embedded form show a white box / nothing at all?

Three usual causes. (1) You pasted into a plain Notion /embed block instead of your builder's HTML or code-injection panel — that block sandboxes iframes and strips raw HTML. (2) Your builder is loading the form inside an iframe and the parent CSS is hiding it with overflow:hidden on the section. (3) Content Security Policy on your builder is blocking the form action. The fix in all three cases is to use the builder's dedicated HTML / Custom Code feature, not Notion's embed primitive.

Can I keep my submissions in Notion as a database?

Yes — splitforms can post each submission to a Notion database via webhook. Set up a webhook in the splitforms dashboard pointing at a small serverless function (or a Zapier / Make zap) that calls the Notion API to insert a database row. We cover the full pattern in the /blog/send-form-submissions-to-notion guide. This way you keep the visual editor as your CMS and still get a real form backend.

What does this cost on splitforms versus the builder's built-in form?

splitforms is 1,000 submissions per month free, $5/mo Pro for 5,000, or $59 for 4 years on the discount plan. Super.so doesn't include a real form backend at all — you either use a third-party widget or paste in HTML. Potion.so and Feather are similar. The realistic comparison is splitforms versus paying Formspree or Getform on top of your builder subscription, where splitforms wins on both free tier and paid tier as of 2026-05.

About the author
✻ ✻ ✻

Get your free contact form API key in 60 seconds.

1,000 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 inbox.

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