# Embedding Forms

Get and use the HTML embed code on your website.

## Get the embed code

1. Open the **Forms** page and click on the form you want to embed.
2. Scroll to the **Embed Code** section on the form detail page.
3. Click the copy icon to copy the snippet to your clipboard.

The embed code is a self-contained HTML snippet: the form markup with inline styles, a hidden
check field, and a small JavaScript block that posts the submission as JSON to
`https://sendbeam.io/api/forms/` and shows the response. It loads no
external script (unless Turnstile is enabled), so it does not slow down your page.

> **What updates automatically and what does not.** The thank-you message and
> redirect URL are returned by SendBeam on every submission, so changing them takes effect
> immediately. The fields, the button label and the Turnstile widget are baked into the snippet
> — copy it again after changing those. The snippet also reports that the form was shown, which is
> what the [conversion rate](https://sendbeam.io/docs/forms#views-and-conversion-rate) is measured against.
> 

## Paste into your site

Paste the snippet wherever you want the form to appear. The form fills the width of its
parent container, so wrapping it in a `` with a max-width gives you
control over how wide it renders.

For the best results, place the form in a location that gets attention:

- Above the fold on a dedicated landing page
- In the sidebar of a blog or article layout
- Within the body of a post, after the first few paragraphs
- In the site footer as a persistent subscribe prompt

## Hosted page

Every active form also has its own page at `https://sendbeam.io/f/` — the link and an
**Open** button sit at the top of the form's page in the app. Use it wherever there is no site to
paste a snippet into: a link in a social bio, a QR code on print, a post, or a client's site you cannot edit.
The page shows the same fields, double opt-in and thank-you message as the embed and carries your workspace name.
Turning the form off (Status → Inactive) takes the page down with it.

It can stand as a page of its own: under **Form settings** give it a **headline**, a
**line of copy**, a **button label** and an **image**, and the page shows
them above the form and uses them as its share preview when the link is posted. The page is not indexed by
search engines unless you tick **Let search engines find the hosted page** on the form; embeds and
pop-ups are never indexed either way.

## Pop-up

Signup forms and contact forms can both open in a modal over any page. Copy the **Pop-up** snippet from
the form's page and put it anywhere in your HTML:

```
<script src="https://sendbeam.io/f/<form id>/popup.js" data-style="split" data-delay="5000" data-once="day" async></script>
```

The form renders inside an iframe of the hosted page, so your site's CSS and ours never interfere. Options are
attributes on the script tag:

- `data-delay` — milliseconds before the modal opens (default 5000; `0` opens at once).
- `data-once` — how long to stay away after a close or a submission: `day` (default), `week`, `forever`, or `never` to show on every visit. Remembered in the visitor's browser.
- `data-trigger="button"` — no timer; show a floating button in the corner instead (`data-label` sets its text).
- `data-trigger="scroll"` / `"exit"` — open at a scroll depth (`data-scroll`, default 60%) or on exit intent.
- `data-trigger="manual"` — no timer and no button; only elements with `data-sendbeam-open` open it.
- Any element with `data-sendbeam-open=""` opens the modal on click, so your own "Subscribe" or "Contact" link can trigger it.

### Styles

A pop-up arrives over whatever somebody was reading, so it has to look like it was made rather
than generated. There are four looks; `split` is the default, and every one of them
uses the colours, radius and type you already pass (see [Customising](https://sendbeam.io/docs/forms/customising)).
On a phone every style becomes a bottom sheet — full width, rounded at the top, the field and
button stacked.

- `data-style` — `split` (default), `editorial`, `bold` or `slide`.
- `data-image` — an `https` picture: the side panel on `split`, the thumbnail on `slide`. Without one, `split` uses your accent colour.
- `data-eyebrow` — the small line above the headline, up to 40 characters (a pill on `bold`).
- `data-button` — the submit button's label, up to 30 characters.
- `data-proof` — `1` adds "Joined by N readers", counted from the list the form adds to. It is hidden until there are enough subscribers for it to help.

The headline and the line under it are `data-heading` and `data-sub`, as before. One example of each:

```
<!-- split: a picture beside the words, 760px -->
<script src="https://sendbeam.io/f/<form id>/popup.js" data-style="split"
  data-image="https://example.com/roastery.jpg" data-eyebrow="Monthly · Free"
  data-heading="Get the roast notes" data-button="Subscribe" async></script>

<!-- editorial: centred, serif headline, with a "No thanks" link -->
<script src="https://sendbeam.io/f/<form id>/popup.js" data-style="editorial"
  data-heading="Before you go — 10% off your first order" data-button="Send my code" async></script>

<!-- bold: your accent colour IS the card -->
<script src="https://sendbeam.io/f/<form id>/popup.js" data-style="bold"
  data-eyebrow="New this month" data-heading="Get the monthly notes" data-proof="1" async></script>

<!-- slide: a small card in the corner, no overlay, the page stays usable -->
<script src="https://sendbeam.io/f/<form id>/popup.js" data-style="slide" data-trigger="scroll"
  data-image="https://example.com/thumb.jpg" data-heading="Roast notes, monthly" data-button="Join" async></script>
```

Every pop-up carries a small "Powered by SendBeam" line. An address that is not `https`,
a style nobody has heard of or copy past its length is ignored rather than rendered, so a typo
costs you the option and not the pop-up.

### Contact forms

A contact form's snippet is the same script with different defaults: `data-trigger="button"` and
`data-label="Contact us"`, so visitors get a floating button that opens the form when they want it, and
nothing is remembered between visits. A contact form is never a timed interruption; set `data-delay`
yourself if you really want one. Messages arrive at your *Send messages to* address exactly as from the
inline form, with the visitor as Reply-To, and the same origin list, rate limits and bot check apply.

> If the form restricts submissions to certain origins, the pop-up only opens on those sites (and on the hosted page itself): the frame is refused elsewhere, which is the same rule the inline embed follows. The plain hosted page is meant to be shared anywhere and is not restricted.
> 

## Platform tips

The process for pasting HTML differs slightly across website builders. Here are quick notes
for the most common platforms:

- **Raw HTML / static sites** — paste directly into the HTML file where you
  want the form to appear.
- **WordPress** — in the Gutenberg editor, add a **Custom HTML**
  block and paste the snippet. For sidebars and footers, use **Appearance > Widgets** and add a **Custom HTML** widget.
- **Webflow** — drag an **Embed** element onto the canvas,
  double-click it to open the code editor, and paste the snippet. Publish your site for
  the form to appear (it will not execute inside the Webflow Designer preview).
- **Squarespace** — add a **Code Block** to the page, paste the
  snippet, and make sure "Display Source" is unchecked. Requires a Business plan or higher.
- **Wix** — use **Add > Embed Code > Custom Embeds > Embed a Widget** and paste the snippet into the code panel.
- **React / Vue / Next.js / Nuxt** — build a native form component that posts
  JSON to the form's endpoint (shown under **API Endpoint** on the form page)
  with `email` and any other fields, plus the hidden check field named on the
  form's Embed tab. The response contains `success`, `message` and
  `redirect_url`.

> **Content Security Policy (CSP) headers** can block the snippet's inline
> script or its request. If the form does not submit, allow inline scripts for it (or move the
> script into your bundle) and add `https://sendbeam.io` to `connect-src`.
> 

## Contact forms and Turnstile

A contact form's embed code has name, email, subject and message fields and a
**Send message** button instead of a subscribe button. Everything else works the
same way: it posts JSON to the form's endpoint and shows the thank-you message on success.

If the form has **Turnstile** enabled (a site key and secret key in its Protection
section), the embed code also includes Cloudflare's widget script and a
``. The widget is invisible to most visitors and
adds a hidden `cf-turnstile-response` field; the snippet sends that value as
`turnstile_token`. SendBeam rejects any submission whose token is missing or
invalid.

> **Content Security Policy.** If your site sends a CSP header, allow
> `https://challenges.cloudflare.com` in `script-src`,
> `frame-src` and `connect-src`, or the widget will not load and every
> submission will be refused.
> 

If you build your own form instead of using the snippet, post the same fields to the endpoint
and include the Turnstile widget yourself. When the form lists **allowed sites**,
the request must come from a browser on one of those origins.

## Test after embedding

Always run a quick end-to-end test after pasting the embed code:

1. Load the page on your live website (not a local preview).
2. Verify the form renders and all fields are visible.
3. Submit the form with a real email address you control.
4. Confirm the success message or redirect appears as expected.
5. Open **Contacts** in SendBeam to verify the new contact was created (and, for a signup form with a list, that they appear on the list).
6. If using double opt-in, check that the confirmation email arrives and the confirmation link works.
7. For a contact form, check the notification arrives at your *Send messages to* address and that pressing reply addresses the visitor.
8. With allowed sites set, a submission from any other origin should be refused with a 403; with Turnstile, one without a token should be refused too.

> Re-run this test after any major website update, theme change, or platform migration.
> Framework hydration, caching layers, or updated CSP rules can silently break an
> embedded form between deploys.
>

---
Source: https://sendbeam.io/docs/forms/embedding
