API
Methods
next.exitIntent(options)
Initialize and activate the exit intent enhancer. Lazy-loads the enhancer on first call and replaces the active config on subsequent calls.
await next.exitIntent({
image: 'https://example.com/popup.webp',
action: () => next.applyCoupon('SAVE10'),
});Returns a Promise<void>. Safe to call inside or after next:initialized.
You must pass either image or template — not neither, not both.
next.disableExitIntent()
Stop listening for exit intent triggers and tear down any active popup. Calling next.exitIntent({...}) again reactivates it.
next.disableExitIntent();Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
image | string | — | URL of an image to display. Required if template is not set |
template | string | — | Name of a <template data-template="..."> element. Required if image is not set |
action | () => void | Promise<void> | — | Callback. In image mode, runs on image click. In template mode, runs only when a data-exit-intent-action="custom" button is clicked |
actionButtonText | string | '' | If set in image mode, renders a CTA button with this text instead of making the image clickable |
imageClickable | boolean | true | In image mode, controls whether the image itself runs the action on click |
disableOnMobile | boolean | true | Disables the enhancer on mobile devices |
mobileScrollTrigger | boolean | false | When mobile is enabled, triggers the popup at 50% scroll instead of mouse-leave |
maxTriggers | number | 1 | Maximum number of times the popup can fire in a session |
overlayClosable | boolean | true | Allow clicking the overlay to dismiss |
showCloseButton | boolean | false | Render an X button on the modal |
useSessionStorage | boolean | true | Persist trigger count and dismissal in sessionStorage |
sessionStorageKey | string | 'next-exit-intent-dismissed' | The sessionStorage key used for persistence |
Mobile is disabled by default. To make exit intent work on mobile, you need both disableOnMobile: false and mobileScrollTrigger: true. Setting only one of them does nothing.
Trigger Logic
Desktop
- Listens for
mouseoutevents ondocument.documentElement - Fires when
clientY <= 10andrelatedTargetis null or<html>(cross-browser way to detect the cursor leaving the viewport top) - Built-in 30-second cooldown between triggers
Mobile (when enabled)
- Listens for
scrollevents onwindow - Fires when scroll percentage
>= 50%ofdocument.body.scrollHeight - window.innerHeight - Built-in 30-second cooldown between triggers
Mobile detection
A device is considered mobile when both are true:
'ontouchstart' in window || navigator.maxTouchPoints > 0(touch-capable)- AND (
window.innerWidth < 768OR the user agent matches/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i)
Session Persistence
When useSessionStorage is true (the default), the enhancer stores:
{
"triggerCount": 1,
"lastTriggerTime": 1712345678901
}at sessionStorage[sessionStorageKey]. Once triggerCount >= maxTriggers, no further triggers fire until the session ends or you clear the key manually.
To reset for testing:
sessionStorage.removeItem('next-exit-intent-dismissed');