Embedding a Form
Add a SayWall collection form to any website — inline in your page, as a centered popup, or as a floating corner widget.
Updated March 12, 2026
Quick Start
Get a collection form on your page in under 5 minutes.
In the SayWall dashboard, go to Forms, open your form, and click the Share tab. Choose your display mode (Inline, Popup, or Floating), configure any options, then copy the embed snippet.
Paste the snippet into your page's HTML. The <script> tag needs to appear only once per page (before </body>). The <div> goes wherever you want the form to render (inline mode) or anywhere on the page (popup and floating modes).
<div data-saywall-collect="YOUR_FORM_ID"></div>
<script src="https://saywall.io/collect-embed.min.js" async></script>Save and reload your page. The script loads asynchronously and won't block your page render. For inline mode the form appears in place. For popup and floating modes, the configured trigger fires automatically.
Display Modes
Pro feature: Inline, popup, and floating embed modes require a Pro plan. The public form page is available on all plans.
SayWall collection forms support three display modes. You choose the mode in the Share tab of the form editor — the embed snippet is generated automatically to match your settings.
| Mode | How it appears | Best for |
|---|---|---|
| Inline | Rendered directly in your page content | Dedicated feedback pages, landing pages |
| Popup | Centered modal overlay with a backdrop | Post-purchase flows, capturing attention |
| Floating | Corner widget that floats over your page | Non-intrusive, persistent collection |
Inline Mode
The default. The form renders in the exact position of the <div>.
<div data-saywall-collect="YOUR_FORM_ID"></div>
<script src="https://saywall.io/collect-embed.min.js" async></script>Popup Mode
The <div> can be placed anywhere — it is invisible. The form opens as a modal overlay based on your trigger settings.
<div
data-saywall-collect="YOUR_FORM_ID"
data-mode="popup"
data-trigger="button"
data-trigger-text="Leave a Review"
data-trigger-position="bottom-right"
data-trigger-color="#4f46e5"
data-trigger-text-color="#ffffff"
data-popup-size="md"
></div>
<script src="https://saywall.io/collect-embed.min.js" async></script>Floating Mode
The form appears as a floating card anchored to a corner of the viewport.
<div
data-saywall-collect="YOUR_FORM_ID"
data-mode="slidein"
data-trigger="button"
data-trigger-text="Leave a Review"
data-trigger-position="bottom-right"
data-slidein-position="bottom-right"
></div>
<script src="https://saywall.io/collect-embed.min.js" async></script>HTML vs React/Next.js
<!-- Place the div where you want the form (inline) or anywhere (popup/floating) -->
<div data-saywall-collect="YOUR_FORM_ID"></div>
<!-- Place the script once per page, before </body> -->
<script src="https://saywall.io/collect-embed.min.js" async></script>Trigger Types
Popup and floating forms fire based on a trigger. You configure the trigger in the dashboard — the attribute is included in the generated embed code automatically.
data-trigger value | Behaviour |
|---|---|
button | Renders a fixed floating button. Clicking it opens the form. |
delay | Opens the form automatically after N seconds. Once per session. |
exit_intent | Opens when the user moves their cursor toward the browser close/back button. Desktop only. Once per session. |
api_only | No automatic trigger. Open and close the form with the JS API. |
delay and exit_intent triggers fire once per browser session using
sessionStorage. If the user closes the form and revisits the page in the
same session, it will not reappear automatically.
Exit intent is desktop-only. Mobile browsers do not expose the cursor
position needed to detect exit intent. If mobile coverage matters, use
button or delay instead.
Data Attributes Reference
Core attributes
| Attribute | Required | Description |
|---|---|---|
data-saywall-collect | Yes | Your form's short ID (copied from the dashboard) |
data-mode | No | inline (default), popup, or slidein |
Trigger attributes (popup and floating modes)
| Attribute | Default | Description |
|---|---|---|
data-trigger | button | Trigger type: button, delay, exit_intent, or api_only |
data-trigger-text | "Leave a Review" | Label on the floating trigger button |
data-trigger-position | bottom-right | Button position: bottom-right, bottom-left, or bottom-center |
data-trigger-color | #4f46e5 | Button background color (hex) |
data-trigger-text-color | #ffffff | Button label color (hex) |
data-trigger-delay | 5 | Seconds before auto-open (only for data-trigger="delay") |
Popup-specific attributes
| Attribute | Default | Description |
|---|---|---|
data-popup-size | md | Dialog width: sm (480 px max), md (560 px max), or lg (640 px max) |
data-popup-close-backdrop | true | Set to "false" to prevent closing by clicking the backdrop |
data-popup-close-esc | true | Set to "false" to prevent closing with the Escape key |
Floating-specific attributes
| Attribute | Default | Description |
|---|---|---|
data-slidein-position | bottom-right | Corner position: bottom-right or bottom-left |
JS API
For popup and floating forms you can open and close the form from your own JavaScript — useful when you want to trigger collection after a user action (e.g., completing a purchase).
// Open the form
SayWall.open("YOUR_FORM_ID", { mode: "popup" });
// Close the form
SayWall.close("YOUR_FORM_ID");SayWall.open() accepts an optional options object:
| Option | Default | Description |
|---|---|---|
mode | "popup" | "popup" or "slidein" |
popupSize | "md" | "sm", "md", or "lg" |
closeOnBackdrop | true | Allow closing by clicking the backdrop |
closeOnEsc | true | Allow closing with the Escape key |
slideinPosition | "bottom-right" | "bottom-right" or "bottom-left" |
To use the JS API without any automatic trigger, set data-trigger="api_only"
on the embed div. No floating button will be rendered — the form opens only
when your code calls SayWall.open().
You cannot call SayWall.open() with a form ID that is already embedded as an
inline form on the same page. The script will log a warning and do
nothing. Use a separate form ID for inline vs overlay embeds.
How It Works
The embed script uses Shadow DOM to render the form in isolation from your page.
When collect-embed.min.js initialises:
- It scans the page for any
data-saywall-collectelements (including ones added dynamically after load) - For inline mode it fetches and renders the form immediately in place
- For popup / floating mode it sets up the configured trigger, then fetches the form when it's about to open
- It attaches a shadow root to the host element and injects the form styles and HTML inside it
The shadow root completely isolates the form's styles from your page — no CSS conflicts in either direction.
CSP Requirements
The collection form embed requires script-src 'unsafe-eval' in your Content Security Policy.
Add this to your Content-Security-Policy header:
script-src 'self' https://saywall.io 'unsafe-eval';
If reCAPTCHA spam protection is enabled on your form, also allow:
script-src 'self' https://saywall.io https://www.google.com/recaptcha/ https://www.gstatic.com/ 'unsafe-eval';
Direct Form Link
Every collection form also has a standalone URL:
https://saywall.io/t/YOUR_PROJECT_SLUG/YOUR_FORM_SLUG
You can share this link directly in emails, QR codes, or social posts — no embed required. The link is shown in the Share tab of the form editor alongside the embed code.
Frequently Asked Questions
Need help?
Have a question or need assistance? Reach us at hello@saywall.io

