Behaviour signals
Exit intent, attention bands, scroll depth, rage clicks and dead clicks — the derived signals autocapture produces without any instrumentation.
Beyond clicks and pageviews, autocapture derives a handful of signals about how a page was used. All of them ride on autocapture, need no instrumentation, and capture positions and durations — never page content.
Exit intent#
$exit_intent fires when a visitor looks like they are leaving — either the
pointer leaves through the top edge of the page, or the page is scrolled upward
hard and fast after real engagement.
The event carries velocity_px_ms, distance_px and exit_y, which exist so
you can tune the thresholds from your own distribution rather than trusting a
default that was a guess:
await ScaleBun.init({ clientKey, apiBaseUrl, exitIntent: { windowMs: 120, // how far back upward velocity is measured minDistancePx: 80, // minimum upward travel — filters micro-corrections minVelocityPxMs: 0.7, // ≈700 px/s — a flick, not a drift minDepthPct: 25, // engagement floor: how far they got first sustainSamples: 3, // consecutive qualifying samples (hysteresis) topEdgePx: 40, // pointer-exit band at the top of the page },});topEdgePx belongs to the pointer trigger, not scroll reversal. mouseout
reports the last sampled pointer position, and a fast flick toward the tab bar
covers tens of pixels between samples — so a narrow band misses exactly the
deliberate gestures it exists to catch. Raise it if pointer exits look
under-reported.
Attention#
The document is split into ten vertical bands, and a coarse timer credits each band by how much of it is on screen. Only time that is both active and visible counts: a backgrounded tab accrues nothing, and so does a page left open while someone is away (15 s without interaction stops the clock).
The summary rides along on $pageleave as attention_bands,
attention_active_ms and attention_bands_n.
This is what separates "they reached the pricing table" from "they read it" — scroll depth answers the first, attention answers the second.
Scroll depth#
Depth is computed at emit time, from the deepest pixel offset reached and the
document height tracked by a ResizeObserver. That matters on any page that
grows: infinite scroll, late-loaded content, virtualized lists. A naive
percentage captured on each scroll is frozen against the height at that instant
and reports the wrong number.
$pageleave carries scroll_depth_pct, max_scroll_px, doc_h, viewport_h,
max_bucket (0/25/50/75/100) and scrollable.
Rage and dead clicks#
$rageclick fires on rapid repeated clicks in the same small area — the
signature of something that looks interactive and is not responding.
$deadclick fires on a click that produced no DOM change, no navigation and no
network request.
Both are strong triage signals precisely because they need no instrumentation: they surface the broken thing you did not know to measure.
Opting out#
Any subtree can be excluded from autocapture entirely:
<div data-scalebun-no-capture> <!-- nothing in here is autocaptured --></div>To keep capture but hide the text on interaction events, set
privacy.maskEventText. See Privacy & consent.
Next#
Product analytics — the autocapture these build on.
Reserved events — the full
$vocabulary.