Paste either snippet into your page — a Custom HTML block on WordPress, Shopify, or Squarespace works too. Both snippets update live as you customize, so what you copy is exactly what you configured.
<!-- Free Exit Intent Popup widget by haynes lab — https://hayneslab.dev/tools/widgets/exit-intent-popup -->
<script data-hl-title="Wait — don't leave empty-handed!" data-hl-message="Get our free website checklist and turn more visitors into customers." data-hl-button-text="Send me the checklist">
/*!
* haynes lab — Exit Intent Popup widget (free)
* Docs & embed code: https://hayneslab.dev/tools/widgets/exit-intent-popup
*/
(function () {
'use strict';
var PREFIX = 'hlw-exit-intent-popup';
var STYLE_ID = 'hlw-exit-intent-popup-styles';
function findScript() {
return document.currentScript ||
document.querySelector('script[src*="widgets/exit-intent-popup.js"]');
}
function injectStyles() {
if (document.getElementById(STYLE_ID)) return;
var css =
'.' + PREFIX + ', .' + PREFIX + ' * { box-sizing: border-box; }' +
'.' + PREFIX + ' { font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;' +
' font-size: 16px; line-height: 1.5; color: #1f2937; }' +
'.' + PREFIX + '__overlay { position: fixed; inset: 0; z-index: 99999; display: flex;' +
' align-items: center; justify-content: center; padding: 20px;' +
' background: rgba(17, 24, 39, 0.6); }' +
'.' + PREFIX + '__overlay--staged { position: absolute; z-index: 10; }' +
'.' + PREFIX + '__dialog { position: relative; width: 100%; max-width: 440px; padding: 36px 32px 44px;' +
' background: #ffffff; border: 1px solid #e5e7eb; border-radius: 12px; text-align: center;' +
' box-shadow: 0 20px 50px rgba(0, 0, 0, 0.25); }' +
'.' + PREFIX + '__close { position: absolute; top: 10px; right: 10px; width: 32px; height: 32px;' +
' border: 0; border-radius: 50%; background: transparent; color: #9ca3af; font-size: 20px;' +
' line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; }' +
'.' + PREFIX + '__close:hover { background: #f3f4f6; color: #4b5563; }' +
'.' + PREFIX + '__close:focus-visible { outline: 2px solid var(--hlw-accent); outline-offset: 2px; }' +
'.' + PREFIX + '__title { margin: 0 0 10px; font-size: 22px; font-weight: 700; color: #111827; }' +
'.' + PREFIX + '__message { margin: 0 0 22px; font-size: 15px; color: #4b5563; }' +
'.' + PREFIX + '__cta { display: inline-block; padding: 12px 26px; border: 0; border-radius: 8px;' +
' background: var(--hlw-accent); color: #ffffff; font-size: 15px; font-weight: 600;' +
' text-decoration: none; cursor: pointer; }' +
'.' + PREFIX + '__cta:hover { filter: brightness(0.92); }' +
'.' + PREFIX + '__cta:focus-visible { outline: 2px solid var(--hlw-accent); outline-offset: 2px; }' +
'.' + PREFIX + '__preview { display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px;' +
' border: 1px dashed #d1d5db; border-radius: 8px; background: #f9fafb; color: #4b5563;' +
' font-size: 13px; cursor: pointer; }' +
'.' + PREFIX + '__preview:hover { border-color: var(--hlw-accent); color: var(--hlw-accent); }' +
'.' + PREFIX + '__preview:focus-visible { outline: 2px solid var(--hlw-accent); outline-offset: 2px; }' +
'.' + PREFIX + '__credit { position: absolute; right: 10px; bottom: 8px; font-size: 11px;' +
' display: inline-flex; align-items: center; gap: 4px; color: #9ca3af; text-decoration: none; }' +
'.' + PREFIX + '__credit svg { display: block; }' +
'.' + PREFIX + '__credit:hover { color: #6b7280; text-decoration: underline; }' +
'@media (max-width: 560px) { .' + PREFIX + '__dialog { padding: 28px 20px 42px; }' +
' .' + PREFIX + '__title { font-size: 19px; } }';
var style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = css;
document.head.appendChild(style);
}
function el(tag, className, text) {
var node = document.createElement(tag);
if (className) node.className = className;
if (text != null) node.textContent = text;
return node;
}
function logoSvg() {
var svgNS = 'http://www.w3.org/2000/svg';
var svg = document.createElementNS(svgNS, 'svg');
svg.setAttribute('viewBox', '0 0 32 32');
svg.setAttribute('width', '13');
svg.setAttribute('height', '13');
svg.setAttribute('aria-hidden', 'true');
svg.setAttribute('focusable', 'false');
function circle(cx, cy, r, attrs) {
var c = document.createElementNS(svgNS, 'circle');
c.setAttribute('cx', cx);
c.setAttribute('cy', cy);
c.setAttribute('r', r);
for (var key in attrs) c.setAttribute(key, attrs[key]);
svg.appendChild(c);
}
circle(16, 16, 16, { fill: '#0f0a0a' });
circle(16, 16, 12, { fill: 'none', stroke: '#fff5f5', 'stroke-width': 1, opacity: 0.3 });
circle(16, 16, 9, { fill: 'none', stroke: '#fff5f5', 'stroke-width': 1, opacity: 0.5 });
circle(16, 16, 6, { fill: 'none', stroke: '#fff5f5', 'stroke-width': 1.2, opacity: 0.9 });
circle(16, 16, 3, { fill: '#06b6d4' });
circle(24.5, 7.5, 2, { fill: '#f97316' });
circle(7, 16, 1.8, { fill: '#f97316' });
circle(20, 20, 1.5, { fill: '#f97316' });
return svg;
}
function build(script) {
var title = script.getAttribute('data-hl-title') || 'Before you go…';
var message = script.getAttribute('data-hl-message') ||
'Join our newsletter and get 10% off your first order.';
var buttonText = script.getAttribute('data-hl-button-text') || 'Claim my discount';
var link = script.getAttribute('data-hl-link') || '#';
var delay = parseInt(script.getAttribute('data-hl-delay'), 10);
if (isNaN(delay) || delay < 0) delay = 5000;
var accent = script.getAttribute('data-hl-accent') || '#f97316';
injectStyles();
var stage = script.closest ? script.closest('.widget-demo__stage') : null;
var storageKey = 'hlw-exit-intent-popup-shown:' + title;
var overlay = el('div', PREFIX + ' ' + PREFIX + '__overlay' + (stage ? ' ' + PREFIX + '__overlay--staged' : ''));
overlay.style.setProperty('--hlw-accent', accent);
overlay.setAttribute('hidden', '');
overlay.style.display = 'none';
var dialog = el('div', PREFIX + '__dialog');
dialog.setAttribute('role', 'dialog');
dialog.setAttribute('aria-modal', 'true');
dialog.setAttribute('aria-label', title);
var close = el('button', PREFIX + '__close', '×');
close.type = 'button';
close.setAttribute('aria-label', 'Close popup');
dialog.appendChild(close);
dialog.appendChild(el('h2', PREFIX + '__title', title));
dialog.appendChild(el('p', PREFIX + '__message', message));
var cta = el('a', PREFIX + '__cta', buttonText);
cta.href = link;
dialog.appendChild(cta);
var credit = el('a', PREFIX + '__credit');
credit.appendChild(logoSvg());
credit.appendChild(document.createTextNode('Powered by haynes lab'));
credit.href = 'https://hayneslab.dev/tools/widgets/exit-intent-popup';
credit.target = '_blank';
credit.rel = 'noopener';
dialog.appendChild(credit);
overlay.appendChild(dialog);
function hide() {
overlay.style.display = 'none';
overlay.setAttribute('hidden', '');
document.removeEventListener('keydown', onKeydown);
}
function onKeydown(e) {
if (e.key === 'Escape') hide();
}
function show(markShown) {
if (markShown) {
try { sessionStorage.setItem(storageKey, '1'); } catch (e) { /* storage unavailable */ }
}
overlay.removeAttribute('hidden');
overlay.style.display = 'flex';
document.addEventListener('keydown', onKeydown);
close.focus();
}
close.addEventListener('click', hide);
overlay.addEventListener('click', function (e) {
if (e.target === overlay) hide();
});
if (stage) {
// Landing-page demo: never auto-trigger, offer a preview button instead.
stage.appendChild(overlay);
var preview = el('button', PREFIX + ' ' + PREFIX + '__preview', 'Preview popup');
preview.type = 'button';
preview.style.setProperty('--hlw-accent', accent);
preview.addEventListener('click', function () { show(false); });
stage.appendChild(preview);
return;
}
// Real page: arm exit-intent once the visitor has been here data-hl-delay ms.
document.body.appendChild(overlay);
var armed = false;
try { armed = sessionStorage.getItem(storageKey) === '1'; } catch (e) { /* ignore */ }
if (armed) return;
setTimeout(function () {
document.addEventListener('mouseleave', function onLeave(e) {
if (e.clientY > 0) return; // only when leaving toward the top of the viewport
document.removeEventListener('mouseleave', onLeave);
show(true);
});
}, delay);
}
function init() {
var script = findScript();
if (!script) {
console.warn('[haynes lab exit-intent-popup] Could not locate its own script tag. Nothing rendered.');
return;
}
build(script);
}
if (document.body) {
init();
} else {
document.addEventListener('DOMContentLoaded', init);
}
})();
</script>