Skip to content

Growth

Exit Intent Without Being Awful — a Bar, a Cap and an Actual Offer

mouseleave at the Top Edge, a localStorage Frequency Cap, and Why a Bar Beats a Modal
Written by Aiden Wood Founder and Lead Design Engineer
🚪 🧲 🤝

Exit-intent popups have the worst reputation of any pattern that demonstrably works. The reputation is earned — but it's earned by the implementation, not the idea: full-screen takeovers, "No thanks, I hate saving money" buttons, firing on every visit forever.

Velocity X ships the non-hostile version as exit-intent-offer-bar — a top-docked bar, not a modal — alongside the heavier lead-capture-popup for when the offer genuinely warrants an interruption.

The Money Pattern

Desktop exit intent is one listener: the pointer leaving through the top of the viewport (toward the URL bar and the close button):

useEffect(() => {
  const KEY = 'exit-offer-dismissed';
  if (localStorage.getItem(KEY)) return;        // frequency cap FIRST

  const onLeave = (e: MouseEvent) => {
    if (e.clientY > 0 || e.relatedTarget) return; // top edge only
    setShow(true);
    document.removeEventListener('mouseout', onLeave);
  };
  const arm = setTimeout(() =>
    document.addEventListener('mouseout', onLeave), 5000); // never instant
  return () => { clearTimeout(arm); document.removeEventListener('mouseout', onLeave); };
}, []);

const dismiss = () => {
  localStorage.setItem('exit-offer-dismissed', String(Date.now()));
  setShow(false);
};

Three load-bearing lines: the cap is checked before anything arms, the listener doesn't arm for the first 5 seconds (someone bouncing in 3 seconds was never converting), and a dismissal is remembered — showing the same bar twice in a session is how you train people to distrust the whole site.

The Catch

Mobile has no cursor, so there is no exit intent — scroll-up-velocity heuristics mostly catch people re-reading the headline. Ship the mobile fallback as a quiet inline section or nothing at all. A timed modal on mobile is also a Google problem: intrusive interstitials carry a documented ranking penalty on mobile results.

And the offer has to be an offer. "Subscribe to our newsletter" is not what someone leaving your pricing page wants; "the free tier is 40 components, here's the repo" might be. No offer? Skip the pattern entirely — an empty interruption is pure cost.

The Verdict

Exit intent is fine; hostility is optional. Bar over modal, 5-second arm, hard frequency cap, real offer — and measure it, because an unmeasured popup is just vandalism with a conversion hypothesis. Both components live in Velocity X's Growth & Conversion category, installed as source you own.

Let us make some quick suggestions?

Please provide your full name.
Please provide your phone number.
Please provide a valid phone number.
Please provide your email address.
Please provide a valid email address.
Please provide your brand name or website.
Please provide your brand name or website.