Skip to content

Exit Intent Popups

Exit Intent popups detect when users are about to leave your page and display targeted offers to keep them engaged. Supports both simple image popups and fully customizable HTML templates.

// Wait for SDK to be fully initialized
window.addEventListener('next:initialized', function() {
console.log('SDK initialized, setting up exit intent...');
// Simple image popup setup
next.exitIntent({
image: 'https://example.com/exit-popup.webp',
action: async () => {
const result = await next.applyCoupon('SAVE10');
if (result.success) {
alert('Coupon applied: ' + result.message);
}
}
});
// Optional: Listen to events for analytics
next.on('exit-intent:shown', (data) => {
console.log('Exit intent shown:', data);
});
});
ParameterTypeDescriptionDefault
imagestringURL of popup image-
templatestringName of template (matches data-template attribute)-
actionfunctionFunction to execute on click/custom action-
showCloseButtonbooleanShow X button on modalfalse
overlayClosablebooleanAllow clicking overlay to closetrue
maxTriggersnumberMaximum times to show per session1
disableOnMobilebooleanDisable on mobile devicestrue
mobileScrollTriggerbooleanEnable scroll trigger on mobile (50% scroll)false
useSessionStoragebooleanRemember dismissal in sessiontrue
sessionStorageKeystringCustom storage key'exit-intent-dismissed'
imageClickablebooleanMake image clickable to trigger actiontrue
actionButtonTextstringText for action button (shows button instead of clickable image)-
// Display popup without any action
function justShowPopup() {
next.exitIntent({
image: 'https://example.com/just-popup.webp'
});
}

No action function needed - just shows the image popup.

When using templates, add special attributes to buttons and links to trigger actions:

AttributeAdditional AttributesDescription
data-exit-intent-action="close"-Closes the modal
data-exit-intent-action="apply-coupon"data-coupon-code="CODE"Applies coupon and closes modal
data-exit-intent-action="custom"-Triggers the custom action function
<template data-template="exit-intent">
<div class="exit-modal-content">
<!-- This content does nothing when clicked -->
<h2>Special Offer!</h2>
<p>Click the buttons below for actions:</p>
<!-- Only these buttons trigger actions -->
<button data-exit-intent-action="apply-coupon" data-coupon-code="SAVE10">
Apply SAVE10 Coupon
</button>
<button data-exit-intent-action="custom">
Custom Action
</button>
<button data-exit-intent-action="close">
Close Modal
</button>
</div>
</template>
<script>
next.exitIntent({
template: 'exit-intent',
action: () => {
// This ONLY runs when clicking elements with:
// data-exit-intent-action="custom"
console.log('Custom action triggered!');
alert('Custom action!');
}
});
</script>
<template data-template="exit-intent-offers">
<div class="exit-offers">
<h2>Choose Your Discount!</h2>
<div class="offer-grid">
<div class="offer">
<h3>10% OFF</h3>
<button data-exit-intent-action="apply-coupon" data-coupon-code="SAVE10">
Apply Code
</button>
</div>
<div class="offer">
<h3>Free Shipping</h3>
<button data-exit-intent-action="apply-coupon" data-coupon-code="FREESHIP">
Get Free Shipping
</button>
</div>
<div class="offer">
<h3>$5 OFF</h3>
<button data-exit-intent-action="apply-coupon" data-coupon-code="FIVER">
Save $5
</button>
</div>
</div>
<button data-exit-intent-action="close" class="close-link">
I don't want to save money
</button>
</div>
</template>

The exit intent system emits several events for analytics and tracking:

next.on('exit-intent:shown', (data) => {
// data.imageUrl - The image URL shown (if using image)
// data.template - The template name (if using template)
console.log('Exit intent displayed:', data);
// Track with analytics
gtag('event', 'exit_intent_shown', {
type: data.template ? 'template' : 'image'
});
});

Fired when popup is displayed.

// Different popups for different pages
window.addEventListener('next:initialized', function() {
const pathname = window.location.pathname;
if (pathname.includes('/product')) {
// Product page - offer discount
next.exitIntent({
image: '/images/10-percent-off.jpg',
action: () => next.applyCoupon('SAVE10')
});
} else if (pathname.includes('/cart')) {
// Cart page - free shipping offer with template
next.exitIntent({
template: 'exit-intent-shipping',
showCloseButton: true
});
} else {
// Other pages - newsletter signup
next.exitIntent({
template: 'exit-intent-newsletter',
overlayClosable: true
});
}
});
function setupDynamicExitIntent() {
const cartData = next.getCartData();
const cartTotal = cartData?.totals?.total?.value || 0;
if (cartTotal === 0) {
// Empty cart - show bestsellers
next.exitIntent({
image: '/images/bestsellers.jpg',
action: () => window.location.href = '/bestsellers'
});
} else if (cartTotal < 50) {
// Small cart - offer percentage discount
next.exitIntent({
template: 'exit-intent-discount-15',
showCloseButton: true
});
} else if (cartTotal < 100) {
// Medium cart - offer free shipping
next.exitIntent({
template: 'exit-intent-free-shipping',
overlayClosable: true
});
} else {
// Large cart - offer free gift
next.exitIntent({
image: '/images/free-gift-100.jpg',
action: async () => {
await next.addItem({ packageId: 99, quantity: 1 }); // Free gift
}
});
}
}
// Call when cart changes
next.on('cart:updated', setupDynamicExitIntent);
// Show exit intent only after user has been on page for 30 seconds
let exitIntentTimer;
window.addEventListener('next:initialized', function() {
exitIntentTimer = setTimeout(() => {
next.exitIntent({
image: '/images/dont-leave-yet.jpg',
action: () => next.applyCoupon('COMEBACK'),
maxTriggers: 1
});
}, 30000); // 30 seconds
});
// Clear timer if user completes checkout
next.on('checkout:started', () => {
clearTimeout(exitIntentTimer);
});
// Different offers based on user segment
function showProfileBasedExitIntent() {
const activeProfile = next.getActiveProfile();
if (activeProfile === 'vip') {
next.exitIntent({
template: 'exit-intent-vip',
showCloseButton: true
});
} else if (activeProfile === 'new-customer') {
next.exitIntent({
image: '/images/first-time-discount.jpg',
action: () => next.applyCoupon('WELCOME20')
});
} else {
next.exitIntent({
template: 'exit-intent-standard'
});
}
}

Customize the exit intent popup appearance with CSS:

/* Exit intent overlay */
[data-exit-intent="overlay"] {
background: rgba(0, 0, 0, 0.8) !important;
}
/* Popup container */
[data-exit-intent="popup"] {
/* Styles are inline but can be overridden */
}
/* Template popup specific */
.exit-intent-template-popup {
background: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}
/* Close button */
[data-exit-intent="close"] {
color: #666;
font-size: 28px;
}
[data-exit-intent="close"]:hover {
color: #000;
}
  1. Desktop Detection (Default)

    • Triggers when mouse leaves top of viewport (clientY <= 10)
    • Uses mouseout event on document.documentElement
    • Enabled by default
  2. Mobile Detection (Opt-in)

    • Disabled by default (disableOnMobile: true)
    • Can enable with mobileScrollTrigger: true
    • Triggers at 50% scroll depth
    • Detects mobile via: touch capability + (mobile width OR mobile user agent)
  3. Mobile Optimization

    • Set disableOnMobile: false to enable on mobile
    • Add mobileScrollTrigger: true for scroll-based trigger
    • Test templates on small screens
    • Consider simpler offers for mobile users
// Enable exit intent on mobile with scroll trigger
next.exitIntent({
template: 'exit-intent-mobile',
disableOnMobile: false, // Enable on mobile
mobileScrollTrigger: true, // Use scroll detection
maxTriggers: 1, // Show only once
showCloseButton: true
});
  1. Choose the Right Method

    • Image popups for quick, visual offers
    • Templates for interactive, complex modals
    • Templates allow dynamic cart data display
  2. Session Management

    • Use maxTriggers: 1 to avoid annoying users
    • Leverage sessionStorage to remember dismissals
    • Different triggers for different pages
    • Reset if user takes desired action
  3. Mobile Optimization

    • Default disableOnMobile: true for desktop-only
    • Enable mobileScrollTrigger sparingly
    • Test template layouts on small screens
    • Simpler offers work better on mobile
  4. Template Best Practices

    • Keep templates hidden with <template> tags
    • Use semantic data-template names
    • Include cart display attributes for dynamic data
    • Test all action buttons thoroughly
    • Provide clear close options
  5. Performance

    • Templates are only cloned when needed
    • Images should be optimized and pre-loaded
    • Use CDN for image hosting
    • Lazy-load the exit intent enhancer
  6. User Experience

    • Don’t trigger immediately - wait for engagement
    • Provide clear value in your offer
    • Make close/dismiss obvious
    • Track conversions to measure effectiveness
// Initialize exit intent
next.exitIntent(options);

The main API method. Pass configuration options to set up the exit intent popup.

// Disable exit intent
next.disableExitIntent();

Disables the exit intent popup and removes event listeners.

// Disable when user starts checkout
next.on('checkout:started', () => {
next.disableExitIntent();
});
// Track exit intent conversion
next.on('exit-intent:action', (data) => {
gtag('event', 'exit_intent_conversion', {
action_type: data.action,
coupon_code: data.couponCode
});
});
  1. Verify SDK is initialized (window.next exists)
  2. Check if disableOnMobile: true is blocking on mobile device
  3. Ensure either image or template is provided
  4. Check console for errors
  5. Verify maxTriggers hasn’t been exceeded
  6. Clear session storage to reset
// Ensure template exists with matching name
<template data-template="exit-intent">
<!-- content -->
</template>
// And matches in JavaScript
next.exitIntent({
template: 'exit-intent' // Must match exactly
});
  • For image popups: Check imageClickable is true (default)
  • For templates: Ensure buttons have data-exit-intent-action attribute
  • Custom actions require data-exit-intent-action="custom"
  • Apply coupon requires data-coupon-code attribute