# Signup forms

Collect subscribers from your website with one line of HTML. Build the form
here, paste the tag once, and edit the form as often as you like — the tag never
changes.

```html
<script src="https://emailbump.com/f.js" data-form="frm_8f2c9a1b3d" async></script>
```

That is the whole integration. No jQuery, no second stylesheet, no account setup
call.

## Why the tag never goes stale

Most signup forms put the form's **markup** in the snippet you copy. Change a
field, a colour or a message, and the copy on your website is out of date until
someone goes back and re-pastes it — which is the most common reason an embedded
form stops matching what you built.

Ours carries a form id and nothing else. The form itself lives here, so every
page it's embedded on picks up your edits on the next load.

## Create one

Open **Audience → Forms** and pick one of the ready-made forms:

| | |
| --- | --- |
| **Newsletter** | An email field and a consent box. The one most sites need. |
| **Inline bar** | Email and button on one line, for a footer or under a post. |
| **Welcome popup** | Opens over the page when someone looks like they're leaving. |
| **Popup with an image** | A picture above the ask. |
| **Two-step popup** | Asks for the yes first, the address second. |
| **Sticky bar** | Pinned along the bottom. |
| **Lead capture** | Work email, name and company, for a demo or a download. |
| **Waitlist** | A card with room to explain what people are joining. |

Each one is a working form — pick the closest and change anything you like. Or
start from blank if you'd rather.

Then pick the list new subscribers join (or **create a new list** right there, if
you don't have one yet), and the **Share** tab gives you the snippet.

New forms are drafts until you publish, so a half-built form is never live at a
URL somebody could already be linking to.

## Where you can put it

**Script** — the default. One tag, renders where you put it. The form is drawn
inside a shadow root, which means your site's CSS can't affect it and it can't
affect your site. Several forms on one page is the normal case, not a special
one.

**Popup, slide-in, sticky bar** — the same tag; the form's *kind* decides the
wrapper. Set a delay, a scroll depth, or exit intent, and how long to stay quiet
after someone dismisses it.

**Iframe** — for platforms that strip `<script>`. It reports its own height, so
it sizes itself instead of scrolling inside a fixed box.

**Plain HTML** — your actual form, markup and styles, ready to paste. Works with
JavaScript switched off; submitting reloads the page rather than showing the
message in place. A captcha needs JavaScript, so a form that asks for one falls
back to the honeypot and the rate limit in this mode. Unlike the other snippets
this one *is* the markup, so re-copy it after you change the form.

**React and Vue** — copy-paste components on the Share tab, no package to
install.

**Two-step** — add a **Step break** on the Fields tab. Everything above it is
step one, everything below it step two. A small first ask converts better than a
big one, so the classic shape is a single button ("Yes, I want the code") and the
email address after it. Both steps ship in the page, so it still works as one
long form if JavaScript never arrives.

**A link or QR code** — every form is also a hosted page at
`emailbump.com/f/your-project/newsletter`. Useful in a bio, an email, or printed
on a card. The permanent `/f/frm_...` link works too and never changes.

WordPress, Webflow, Squarespace, Shopify, Wix and Ghost all accept the script
tag or the iframe.

## Double opt-in

New forms ask people to confirm by email. It's the default because it's the best
thing you can do for deliverability, and because it means a bot-submitted
address never reaches your list.

- Someone submits → they get one email → they click → they're subscribed.
- **One email, however many lists the form feeds.** A form pointed at three
  lists doesn't put three confirmations in someone's inbox.
- Until they confirm they aren't marketing-subscribed, so campaigns don't go to
  them.
- If the same address is submitted again within a day, we don't send a second
  email. That stops your form being used to flood somebody's inbox — and their
  original link still works.

Prefer to skip it? **Behaviour → Confirmation** offers *Single* (subscribe now,
send a welcome) and *None* (subscribe now, send nothing).

## Consent, recorded properly

If your form has a consent checkbox, we store the exact wording shown at the
time, along with the timestamp, IP address and the page it was on — and repeat
that wording in the confirmation email.

That matters because a form's wording changes over time, and "what did this
person actually agree to?" is the question you need answered when a complaint
arrives. You don't have to remember to set this up; it's what the consent field
does.

Two attributes are set on every form signup, so you can segment on them straight
away:

- `signup_source` — the form's name
- `double_opt_in` — whether they confirmed by email

## Keeping spam out

A signup form is a public endpoint that can send email, so every submission goes
through:

- a hidden honeypot field, and a check that the form wasn't submitted faster
  than a human could;
- a signed token proving the form was actually rendered;
- rate limits per address and per network;
- disposable-address blocking, on by default;
- optional blocking of free providers (Gmail, Outlook) and shared mailboxes
  (`info@`, `sales@`);
- **Cloudflare Turnstile**, on by default — no puzzles, most people never see it.

Disposable and free-provider blocking are included on every plan, free ones too.

Under **Protection** you can also pin a form to specific domains, so it only
accepts submissions from your own site.

## Styling many forms at once

Forms inherit from a **theme** — colours, font, corner radius, button shape,
spacing. A form stores only what it overrides, so a footer form that needs to be
narrower keeps inheriting everything else.

Change the theme and every form on it restyles, live, with nothing to re-embed.
That's the difference between a rebrand being one edit and twelve.

### Dark mode

By default a form follows the visitor's own preference: any colour you haven't
chosen gets a dark counterpart, so labels stay readable on a dark page and the
inputs don't glare. Colours you *did* choose are kept in both — your brand accent
shouldn't change because someone's laptop is in night mode.

If a form only ever sits on a light page (or only a dark one), set **Dark mode**
to *Always light* / *Always dark* under Design and it stops adapting.

Themes belong to a project. To use the same brand in another project, copy it —
the copy is independent from then on.

## Where it appears, and to whom

The **Targeting** tab decides whether a page view qualifies at all — separate
from the trigger, which decides when within one that does.

- **Show on these pages** — URL rules that *contain*, *are exactly*, *start with*
  or *end with* what you type. No rules means everywhere.
- **Except these** — checked last and always wins, which is how you say
  "everywhere but checkout".
- **Who sees it** — everyone, first-time visitors only, or returning visitors
  only.
- **How often** — until they subscribe (the default), once ever, or every visit.

For a popup, slide-in or sticky bar there's also **when**: after a number of
seconds, once they've scrolled past a point, or when they look like they're
leaving. Set none of the three and it appears on load. A dismissal rests it for
the number of days you choose; subscribing retires it for good.

Whether someone has seen it is remembered in their own browser, so clearing site
data or switching device starts them over.

## Watching it work

The Forms page counts three things, and the gaps between them are where the
answers are:

- **Shown** — times the form was actually displayed. Counted when it appears,
  not when the page loaded, so a popup whose trigger never fires isn't counted.
- **Submissions** — how many people filled it in. Against *shown*, that's the
  number a popup's placement and copy are judged on.
- **Contacts** — how many became subscribers. The gap from *submissions* is your
  double-opt-in confirmation rate; a wide one usually means the confirmation
  email isn't landing, not that people changed their minds.

Open a form to see individual submissions, including rejected ones and why.

## Automations

Use the **Form submitted** trigger to start a flow — a welcome sequence, a
notification to your team, a tag. For a double-opt-in form it fires when they
confirm, not when they submit, so a sequence never starts for someone who never
agreed to hear from you.

There's also a one-click **email me on each submission** toggle under Behaviour.

## From code

Forms are a full API resource — see the [Forms API](/docs/forms-api) — and
available from the CLI and the MCP server:

```bash
emailbump forms:create --name "Newsletter" --list LIST_ID --double-optin
emailbump forms:embed frm_8f2c9a1b3d --as script >> src/components/Footer.astro
```

## Common questions

**Why isn't the person appearing in my list?** With double opt-in they only join
after clicking the link in their email. Check the form's submissions — a row
sitting at `pending_confirmation` means the email went out and hasn't been
clicked yet.

**I edited the form; do I need to update my website?** No. That's the point.

**Can I use several forms on one page?** Yes, any number, each with its own
theme.

**Does it work without JavaScript?** Use the plain HTML snippet. You lose the
captcha and the inline success message; everything else still applies.
