Popups still work when done right.
The word "popup" triggers reflexive eye-rolls from web designers and UX purists. But the data tells a different story. The average popup conversion rate across e-commerce sites is 3.09%, according to OptiMonk's 2025 analysis of 1 billion popup impressions. The top 10% of popups convert at 9.28%. For context, the average Shopify store converts 1.3% of visitors into buyers. A well-timed email capture popup can build a list that generates revenue for years — without a monthly app subscription eating into your margins.
This guide gives you free, copy-paste popup code for three use cases: email capture, exit intent, and announcement popups. No apps needed. You will also learn the timing rules that separate effective popups from annoying ones, and when an app genuinely makes more sense than custom code.
What Is a Shopify Popup and How Does It Affect Conversions?
A Shopify popup is a modal overlay that appears on top of page content, triggered by time delay, scroll depth, exit intent, or user action. According to Sumo's analysis of 2 billion popups, the average conversion rate is 3.09%, with the top-performing popups reaching 9.28%. E-commerce email popups specifically generate $42 in revenue for every $1 invested in email marketing, per DMA's 2024 ROI report, making them the highest-ROI acquisition channel available to Shopify merchants.
A popup is simply a content overlay. What makes it effective or annoying is entirely about timing, relevance, and design. The three most common types on Shopify stores:
- Email capture popups: Offer a discount (typically 10-15%) in exchange for an email address. This builds your owned marketing channel.
- Exit intent popups: Appear when the mouse moves toward the browser's close button (desktop) or after a back-button tap (mobile). Last chance to convert an abandoning visitor.
- Announcement popups: Inform visitors about sales, shipping deadlines, or policy changes. No input required — just an acknowledgment.
| Popup Type | Avg. Conversion Rate | Best Timing | Revenue Impact |
|---|---|---|---|
| Email capture (with discount) | 4-6% | 5-8 seconds on page | High (list building) |
| Email capture (no discount) | 1-3% | 10-15 seconds | Medium (list building) |
| Exit intent | 2-4% | Mouse exits viewport | Medium (saves abandons) |
| Announcement (sale) | N/A (no conversion) | Immediate | Low-medium (awareness) |
| Spin-to-win / gamified | 6-12% | 5-10 seconds | High (engagement + list) |
The critical thing to understand: popup performance is not binary. A popup that appears instantly on page load with an irrelevant offer will annoy visitors and increase bounce rate. The same popup, delayed by 8 seconds and shown only to first-time visitors who have scrolled past 50% of the page, will convert 5-8% of viewers.
For stores already using announcement bars for promotions, a popup serves a different purpose — the announcement bar maintains ambient awareness, while the popup demands a specific action at a strategic moment.
How Do You Build a Simple Email Capture Popup with Code?
A functional email capture popup requires three components: an HTML structure with a form and close button, CSS for modal positioning and responsive design, and JavaScript for display timing and form submission. The complete implementation is approximately 80 lines of code total. When connected to Shopify's customer API or a service like Klaviyo via webhook, captured emails flow directly into your marketing automation system.
Here is the complete, production-ready email capture popup. Copy this code and add it to your Shopify theme.
Step 1: Add the HTML.
Go to Online Store > Themes > Edit Code > Layout > theme.liquid. Paste this just before the closing </body> tag:
<!-- Email Capture Popup -->
<div id="lb-popup-overlay" class="lb-popup-overlay" style="display:none;">
<div class="lb-popup-modal" role="dialog" aria-modal="true" aria-labelledby="lb-popup-title">
<button class="lb-popup-close" aria-label="Close popup">×</button>
<div class="lb-popup-content">
<h2 id="lb-popup-title">Get 10% Off Your First Order</h2>
<p>Join our email list for exclusive deals and early access to new products.</p>
<form id="lb-popup-form" class="lb-popup-form">
<input
type="email"
name="email"
placeholder="Enter your email"
required
autocomplete="email"
class="lb-popup-input"
>
<button type="submit" class="lb-popup-submit">Claim My Discount</button>
</form>
<p class="lb-popup-disclaimer">No spam. Unsubscribe anytime.</p>
</div>
</div>
</div>
Step 2: Add the CSS.
Add this to your theme's CSS file or in a <style> block in theme.liquid:
.lb-popup-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.55);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
animation: lbFadeIn 0.3s ease;
}
@keyframes lbFadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.lb-popup-modal {
background: #fff;
border-radius: 12px;
padding: 40px;
max-width: 440px;
width: 90%;
position: relative;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
animation: lbSlideUp 0.3s ease;
}
@keyframes lbSlideUp {
from { transform: translateY(30px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.lb-popup-close {
position: absolute;
top: 12px;
right: 16px;
background: none;
border: none;
font-size: 28px;
cursor: pointer;
color: #6B7280;
line-height: 1;
padding: 4px 8px;
}
.lb-popup-close:hover {
color: #1F2937;
}
.lb-popup-content h2 {
font-size: 24px;
margin: 0 0 12px;
color: #1F2937;
}
.lb-popup-content p {
color: #6B7280;
margin: 0 0 20px;
font-size: 15px;
line-height: 1.5;
}
.lb-popup-input {
width: 100%;
padding: 14px 16px;
border: 1px solid #D1D5DB;
border-radius: 8px;
font-size: 16px;
margin-bottom: 12px;
box-sizing: border-box;
}
.lb-popup-input:focus {
outline: none;
border-color: #2563EB;
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}
.lb-popup-submit {
width: 100%;
padding: 14px;
background: #1F2937;
color: #fff;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s ease;
}
.lb-popup-submit:hover {
background: #374151;
}
.lb-popup-disclaimer {
font-size: 12px;
color: #9CA3AF;
text-align: center;
margin-top: 12px;
margin-bottom: 0;
}
@media (max-width: 480px) {
.lb-popup-modal {
padding: 28px 20px;
width: 95%;
border-radius: 8px;
}
.lb-popup-content h2 {
font-size: 20px;
}
}
Step 3: Add the JavaScript.
This handles timing, display rules, and form submission:
(function() {
var POPUP_DELAY = 7000; // 7 seconds
var COOKIE_DAYS = 30; // Don't show again for 30 days
var COOKIE_NAME = 'lb_popup_dismissed';
function getCookie(name) {
var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
return match ? match[2] : null;
}
function setCookie(name, value, days) {
var d = new Date();
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
document.cookie = name + '=' + value + ';expires=' + d.toUTCString() + ';path=/;SameSite=Lax';
}
function showPopup() {
var overlay = document.getElementById('lb-popup-overlay');
if (overlay) {
overlay.style.display = 'flex';
document.body.style.overflow = 'hidden';
}
}
function hidePopup() {
var overlay = document.getElementById('lb-popup-overlay');
if (overlay) {
overlay.style.display = 'none';
document.body.style.overflow = '';
setCookie(COOKIE_NAME, '1', COOKIE_DAYS);
}
}
// Don't show if already dismissed
if (getCookie(COOKIE_NAME)) return;
// Show after delay
setTimeout(showPopup, POPUP_DELAY);
// Close button
var closeBtn = document.querySelector('.lb-popup-close');
if (closeBtn) closeBtn.addEventListener('click', hidePopup);
// Click outside to close
var overlay = document.getElementById('lb-popup-overlay');
if (overlay) {
overlay.addEventListener('click', function(e) {
if (e.target === overlay) hidePopup();
});
}
// Escape key to close
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') hidePopup();
});
// Form submission
var form = document.getElementById('lb-popup-form');
if (form) {
form.addEventListener('submit', function(e) {
e.preventDefault();
var email = form.querySelector('input[name="email"]').value;
// Send to your email service (Klaviyo example)
// Replace LIST_ID and API_KEY with your values
fetch('https://a.]klaviyo.com/api/v2/list/LIST_ID/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
api_key: 'YOUR_PUBLIC_API_KEY',
profiles: [{ email: email }]
})
});
// Show success message
var content = document.querySelector('.lb-popup-content');
content.innerHTML = '<h2>You are in!</h2><p>Check your email for your 10% discount code.</p>';
setTimeout(hidePopup, 3000);
});
}
})();
Replace the Klaviyo API endpoint with your actual email service provider. For Mailchimp, Drip, or ConvertKit, substitute the appropriate API endpoint and payload format.
How Do You Add Exit Intent Detection to Your Popup?
Exit intent technology detects when a visitor is about to leave the page by tracking mouse movement toward the browser's address bar or close button (on desktop) or back-button behavior and rapid scrolling (on mobile). According to OptinMonster's case study data, exit intent popups recover 10-15% of otherwise lost visitors. The JavaScript implementation adds approximately 15 lines of code to your existing popup script.
Exit intent is the last line of defense before a visitor leaves. On desktop, it works by monitoring mouse position. When the cursor moves above the page viewport (toward the browser controls), the popup triggers.
Add this to your popup JavaScript:
// Exit Intent Detection (Desktop)
var exitIntentShown = false;
document.addEventListener('mouseout', function(e) {
if (exitIntentShown) return;
if (getCookie(COOKIE_NAME)) return;
// Detect mouse leaving through the top of the viewport
if (e.clientY <= 0 && e.relatedTarget === null) {
exitIntentShown = true;
showPopup();
}
});
// Mobile Exit Intent (scroll-up detection)
var lastScrollY = 0;
var scrollUpCount = 0;
window.addEventListener('scroll', function() {
var currentScrollY = window.scrollY;
if (currentScrollY < lastScrollY && currentScrollY > 300) {
scrollUpCount++;
if (scrollUpCount >= 3 && !exitIntentShown && !getCookie(COOKIE_NAME)) {
exitIntentShown = true;
showPopup();
}
} else {
scrollUpCount = 0;
}
lastScrollY = currentScrollY;
});
The mobile detection is less precise than desktop. There is no mouse cursor to track, so the code watches for a pattern of upward scrolling (three consecutive scroll-up events while past the 300px mark). This correlates with someone scrolling back to the top to navigate away.
Exit intent timing considerations:
| Rule | Implementation | Why It Matters |
|---|---|---|
| Show only once per session | Cookie or sessionStorage | Repeated exit popups feel hostile |
| Skip if timed popup already shown | Check exitIntentShown flag | Two popups per visit is too many |
| Minimum time on page: 10 seconds | setTimeout guard | Instant exit popups catch misclicks |
| Skip on mobile for first visit | User-agent check | Mobile exit detection is unreliable |
| Never show on checkout pages | URL path check | Interrupting checkout kills conversions |
For stores running the Promo Code Display snippet, consider showing the promo code inside your exit intent popup. A visitor who was going to leave without buying now has an immediate reason to reconsider — and the code is already visible on the product page when they close the popup.
How Do You Control Popup Timing and Frequency?
Popup timing is the single largest factor in conversion rate. OptiMonk's data shows that popups delayed 8 seconds convert 3.62% on average, while popups appearing within 2 seconds convert only 1.78% — a 103% performance gap. Frequency capping (showing no more than one popup per 30-day window per visitor) and page-specific targeting further improve performance by reducing popup fatigue.
Timing separates popups that build your business from popups that drive visitors away.
Optimal timing by popup type:
- Email capture: 5-8 second delay for returning visitors, 10-15 seconds for first-time visitors. First-timers need more page time to develop enough interest to warrant sharing their email.
- Exit intent: No delay (triggered by behavior, not time).
- Announcement: Immediate or 2-3 seconds. These are informational, so early display is acceptable.
Frequency rules:
- One popup per visit, maximum. Never stack a timed popup with an exit intent popup in the same session.
- 30-day cookie minimum. After a visitor dismisses a popup or submits the form, do not show any popup again for at least 30 days.
- Separate cookies for dismissal vs. submission. A visitor who submitted their email should never see the email popup again. A visitor who dismissed it might see it on their next visit.
Page-specific targeting:
Not every page deserves a popup. Exclude these:
// Pages where popups should never appear
var excludedPaths = ['/checkout', '/cart', '/account', '/policies'];
var currentPath = window.location.pathname;
var shouldExclude = excludedPaths.some(function(path) {
return currentPath.startsWith(path);
});
if (shouldExclude) return; // Skip popup entirely
Include popups on:
- Homepage (high traffic, low intent — perfect for email capture)
- Collection pages (browsing visitors with moderate intent)
- Blog posts (readers who may not have seen your products yet)
Consider skipping popups on product pages — visitors there already have high purchase intent, and interrupting that focus can reduce conversions. Instead, use inline elements like LiquidBoost's Customer Love Social Proof snippet that reinforce buying signals without blocking the page.
Want conversion elements that work alongside your popups? LiquidBoost's Scrolling Announcement Bar runs persistently without interrupting browsing, while the Availability Indicator snippet creates urgency directly on the product page. These ambient conversion tools complement popups by working in the background. Explore all snippets.
How Do You Connect Your Popup Form to an Email Marketing Service?
Popup form submissions need to flow into your email marketing platform (Klaviyo, Mailchimp, Omnisend, or others) for automated follow-up sequences. The connection happens through a JavaScript API call on form submission. Klaviyo's public API accepts list subscriptions via a simple POST request with no server-side code required. Stores using email automation generate 320% more revenue from email than those sending manual campaigns, per Omnisend's 2024 benchmark data.
The popup collects the email. Your email platform does the heavy lifting — sending the discount code, nurturing the subscriber, and driving repeat purchases.
Klaviyo integration (most common for Shopify):
Replace the fetch call in the form submission handler:
fetch('https://a.klaviyo.com/api/v2/list/YOUR_LIST_ID/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
api_key: 'YOUR_PUBLIC_API_KEY',
profiles: [{ email: email, source: 'Website Popup' }]
})
});
Find your List ID in Klaviyo under Lists & Segments. Your public API key is in Account > Settings > API Keys.
Mailchimp integration:
Mailchimp requires a server-side proxy because their API does not support CORS from browser JavaScript. The simplest approach: use Mailchimp's embedded form action URL:
var form = document.createElement('form');
form.method = 'POST';
form.action = 'https://YOUR_DOMAIN.us1.list-manage.com/subscribe/post';
form.target = '_blank';
// Add hidden fields for u and id values from your Mailchimp form
Shopify Customer API (no external service):
If you do not use an email platform yet, capture emails as Shopify customers:
fetch('/contact', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'form_type=customer&utf8=%E2%9C%93&customer%5Bemail%5D=' +
encodeURIComponent(email) +
'&customer%5Btags%5D=popup-subscriber'
});
This creates a customer record with the tag "popup-subscriber," which you can use for segmentation in Shopify Email or export to any platform later.
When Should You Use a Popup App Instead of Custom Code?
Popup apps make sense when you need A/B testing across multiple popup variants, advanced targeting rules (geo-location, referral source, cart value), built-in analytics dashboards, or visual drag-and-drop popup builders. The trade-off is cost ($10-80/month) and performance impact (apps inject 50-200KB of external JavaScript). For stores with under 10,000 monthly visitors running a single popup, custom code is lighter and more cost-effective.
Custom code is not always the right answer. Here is when to consider an app.
| Factor | Custom Code | Popup App |
|---|---|---|
| Monthly cost | $0 | $10-80/month |
| Page speed impact | Minimal (5-10KB) | Moderate (50-200KB) |
| A/B testing | Manual (requires coding) | Built-in |
| Targeting rules | Basic (page, time, cookie) | Advanced (geo, source, cart) |
| Analytics | Manual (requires GA events) | Built-in dashboard |
| Design flexibility | Unlimited (if you code CSS) | Template-based |
| Maintenance | You maintain it | App maintains it |
| Number of popups | Manageable for 1-3 | Better for 5+ popups |
Recommended apps (when you need one):
- Privy: Free plan available, good Shopify integration, straightforward email capture
- OptiMonk: Advanced targeting, AI-powered optimization, higher learning curve
- Justuno: Strong A/B testing, gamification options, mid-range pricing
- Klaviyo Forms: If you already use Klaviyo for email, their built-in forms avoid adding another third-party script
The decision framework is straightforward: if you need one email capture popup with basic timing, use the custom code from this guide. If you need multiple popups with different targeting rules, A/B testing across variants, and a visual editor for non-technical team members, use an app.
For either approach, pair your popup with on-page elements that reinforce the offer. LiquidBoost's Price Bubble snippet and Trust Marks snippet build purchase confidence that makes the popup's discount offer even more compelling.
What Legal and UX Guidelines Should Your Popup Follow?
GDPR (EU), CCPA (California), and CASL (Canada) require explicit consent before adding visitors to marketing email lists, with clear opt-in language and easy unsubscribe access. From a UX perspective, Google penalizes intrusive interstitials on mobile with lower search rankings since January 2017. Popups must be dismissible within one tap/click, must not cover more than 30% of the screen on mobile before interaction, and should never appear during checkout.
Legal compliance and user experience are intertwined. A popup that violates privacy laws or annoys Google hurts your store twice.
Legal requirements:
- Include opt-in language. "By subscribing, you agree to receive marketing emails" must appear near the submit button.
- Link to your privacy policy. Add a small text link below the form.
- Never pre-check the consent checkbox. If you use a checkbox, it must start unchecked.
- Process unsubscribe requests within 10 business days (CAN-SPAM) or immediately (GDPR).
- Store consent records. Your email platform handles this, but verify it logs when and how each subscriber opted in.
Google's mobile popup rules:
Google's interstitial penalty applies to popups that:
- Cover the main content immediately on page load
- Require dismissal before accessing content
- Use the above-the-fold area as a standalone interstitial
What is safe:
- Popups triggered by user action (clicking a button)
- Popups that use a small banner (not full-screen)
- Cookie consent banners (legally required, exempt from penalty)
- Age verification gates (legally required, exempt)
External reference: Google's interstitial guidelines detail exactly which popup patterns trigger ranking penalties.
For Shopify stores ranking well in search thanks to solid SEO setup, protecting those rankings from popup-related penalties is essential. A small, delayed popup that does not cover content on mobile keeps both Google and your visitors satisfied.
Frequently Asked Questions
Do popups hurt my Shopify store's SEO?
Only if they violate Google's intrusive interstitial guidelines. Full-screen popups that appear immediately on mobile page load can trigger a ranking penalty. Popups that appear after a time delay, cover less than 30% of the mobile screen, or are triggered by user action (like a button click) are safe. Google explicitly exempts cookie consent banners and age verification gates from this policy.
What is the best popup timing for Shopify stores?
Data consistently shows 5-8 seconds produces the highest conversion rates for email capture popups. Popups appearing in under 2 seconds convert 50% worse because visitors have not yet engaged with your content. For exit intent popups, there is no time delay — they trigger on behavior. Set a minimum session time of 10 seconds before allowing exit intent to prevent triggering on accidental page bounces.
Can I add a popup to specific Shopify pages only?
Yes. Wrap your popup JavaScript in a URL path check. For example, to show only on collection pages, check if window.location.pathname starts with /collections/. To show only on the homepage, check if the pathname equals /. You can also use Shopify's Liquid template detection to conditionally render the popup HTML only on specific page templates using {% if template %} conditions.
How do I A/B test popups without an app?
Create two popup variations in your code and randomly assign visitors to one version using a coin-flip function: Math.random() < 0.5. Track each version's submissions using Google Analytics custom events with a variation parameter. Run the test for at least 1,000 popup impressions per variation (typically 2-4 weeks) to reach statistical significance. This manual approach works for testing one variable at a time.
Why is my Shopify popup not showing on mobile?
Three common causes: the popup CSS uses fixed positioning without mobile viewport units (use dvh instead of vh), the JavaScript mouseout event only fires on desktop (add scroll-based mobile detection), or your popup's z-index is lower than your theme's mobile menu overlay. Test by adding !important to z-index: 99999 temporarily. Also check that your popup container is not inside an element with overflow: hidden on mobile breakpoints.
Keep Reading
- Shopify Exit Intent Popup Strategies
- Shopify Announcement Bar: Complete Setup Guide
- How to Boost Shopify Conversion Rates Without Developers
The line between a popup that builds your business and one that damages it is exactly 5 seconds. That delay — the time between a visitor arriving and your popup appearing — determines whether they see a helpful offer or an unwelcome interruption. The code is the easy part. The restraint is what separates the 9% converters from the 1% converters.