Analyze or choose a template
Start with the website analyzer to create a brand kit, or open a design directly from the template library.
Docs
Getting a popup live takes one script tag. Here's the whole process, plus platform notes and troubleshooting.
Start with the website analyzer to create a brand kit, or open a design directly from the template library.
A popup only renders on your site once its status is published. Drafts and paused popups are intentionally invisible to visitors.
Click Embed in the builder to get the snippet containing your own data-popup-id. Every popup has a unique ID.
Add it once, just before the closing </body> tag. After that, edits you make in the builder go live without touching your site again.
The snippet
Replace the domain with your Bonpopup host and the popup ID with your own.
<!-- Bon Popup Code starts -->
<script async src="https://yourdomain.com/popup.js" data-popup-id="popup_101"></script>
<!-- Bon Popup Code Ends -->src — the popup engine script, served from your Bonpopup host at /popup.js.data-popup-id — required. The public ID of the popup to render, e.g. popup_101. Without it the script exits quietly.async — recommended, so the script never blocks rendering.By platform
The tag is the same everywhere. Only the place you put it changes.
Paste directly before the closing </body> tag.
<!DOCTYPE html>
<html lang="en">
<head>
<title>My site</title>
</head>
<body>
<!-- your page content -->
<!-- Bon Popup Code starts -->
<script async src="https://yourdomain.com/popup.js" data-popup-id="popup_101"></script>
<!-- Bon Popup Code Ends -->
</body>
</html>footer.php, or use a header/footer scripts plugin.</body>.On a block theme without footer.php, a footer-scripts plugin is the safer route than editing templates.
layout/theme.liquid.</body> and save.It applies across every page that uses that layout, including product and cart pages.
Use the framework's script component so it loads after hydration.
import Script from "next/script";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://yourdomain.com/popup.js"
data-popup-id="popup_101"
strategy="afterInteractive"
/>
</body>
</html>
);
}Advanced features
These features configure themselves inside the builder. Here's how they work at a glance.
Choose in Appearance → Display mode:
#offer-slot). No floating behavior.Configure in Content → Countdown timer.
Replaces the standard CTA with a canvas-drawn prize wheel. Set 2–8 segments with labels, coupon codes, and probability weights. The spin is animated and the result fires a conversion event.
Configure in Content → Gamification wheel.
Add up to 5 follow-up screens after the initial CTA click. Each step has its own heading, description, and action (advance / open link / close).
Use cases: onboarding surveys, progressive disclosure, qualification funnels.
Configure in Content → Multi-step flow.
Insert {{placeholder}} in any text field. Resolved at runtime per visitor:
{{page_path}}, {{page_title}}, {{domain}}{{visitor_type}} (new/returning), {{traffic_source}} (direct/search/social/referral){{day_of_week}}, {{month}}, {{date}}, {{year}}{{utm_source}}, {{utm_medium}}, {{utm_campaign}}Example: Welcome, {{visitor_type}} visitor! Happy {{day_of_week}}.
A small floating pill that stays on the page. Can appear before the trigger fires (as an alternative entry point) and/or after the popup is dismissed (so visitors can reopen it).
Configure in Behaviour → Teaser tab.
A testimonial quote or activity counter shown below the CTA. Optional 1–5 star rating. Configure in Content → Social proof.
Set a goal URL path (like /thank-you) in Targeting → Conversion goal. A conversion event fires automatically when a visitor who saw the popup navigates to that page — no custom code needed.
Enable in the builder sidebar. Traffic is split between Control A and Variant B using a sticky visitor hash. Analytics shows per-arm impressions, clicks, conversions, and uplift. Promote the winner with one click.
Set optional start and end dates in Behaviour. The popup auto-activates and auto-expires without manual publish/pause. The embed script receives active: false outside the window.
To use embedded mode, add a container element on your page:
<div id="popup-container"></div>Then set #popup-container as the CSS selector in Appearance → Display mode → Embedded inline. The popup content renders inside that div.
Troubleshooting
Work through these in order:
published, not draft or paused.data-popup-id matches your popup exactly.popup.js returns 200 rather than 404.Add a separate script tag per popup ID. Each tag manages its own popup independently.
Yes. Point the script src at your running instance and leave the domain allowlist empty while testing.
The tag is async and the popup config is fetched separately after load, so it never blocks first render.
Set its status to paused in the builder. The script stays in place and renders nothing until you publish again. You can also use scheduling to auto-expire.
Each popup has an analytics page showing impressions, CTA clicks, conversions, audience breakdowns, and A/B experiment results.
It stores the timer start in the visitor's sessionStorage. Refreshing the page doesn't reset it. A new browser session starts a fresh timer.
Dynamic text resolves client-side, so you'll see the raw {{placeholders}} in the builder preview. Publish to a test domain to see them resolve with real visitor data.
A new run ID is created, and visitors are re-randomized. Old run data remains in analytics under the historical run selector.
Send us the page you're embedding on and we'll take a look.
We usually reply within one business day.