Explore documentation
JavaScript tag events
Complete reference of every web event generated by the JavaScript tag.
Envelope structure
Every event stored in ClickHouse (t130_replays_metrics_v3_web_events) shares the same top-level envelope:
| Field | Type | Notes |
|---|---|---|
dt |
Number | Unix timestamp (ms) when the event was captured client-side |
event |
String | Event type name (see sections below) |
payload |
Object | Event-specific data |
session_id |
UUID | Session identifier, rotated after session_timeout_ms of inactivity |
anonymous_user_id |
UUID | Stable anonymous user identifier persisted in localStorage |
user |
Object? | Present only if betterstack('user', {...}) was called. Contains whatever was passed. |
fingerprint |
Array? | Present only if FingerprintJS is configured. Array with one "v1_<hash>" string. |
_app_id |
Number | Internal app identifier (added server-side) |
_ip_addresses |
Array | Client IP addresses (added server-side) |
contexts |
Object? | Browser/OS/device info. Present on autocapture events only (not on memory, user-agent-specific-memory, session-start, or custom events). |
contexts object (when present)
Shared payload.meta (autocapture events only)
All autocapture events (click, dblclick, contextmenu, tap, input, change, submit, reset, page-load, page-change, page-leave, rage-click) include this meta block in payload:
Event types
| Event | Plugin | Description |
|---|---|---|
session-start |
SessionConfigGenerator | Marks the beginning of a new session. Includes UTM params, referrer, and fingerprint data. |
page-load |
PageViewPlugin | Initial full page load (window.load). |
page-change |
PageViewPlugin | In-app SPA navigation (pushState, replaceState, popstate, hashchange). |
page-leave |
PageViewPlugin | Tab close or full navigation away (beforeunload). |
click |
TapPlugin | Left-click on non-touch devices. |
dblclick |
TapPlugin | Double-click on non-touch devices. |
contextmenu |
TapPlugin | Right-click (all devices). |
tap |
TapPlugin | Touch start on touch devices. |
rage-click |
RageClickPlugin | 5+ clicks within 8px / 2s β indicates user frustration. |
input |
FormPlugin | Keystroke or value change in a form element. |
change |
FormPlugin | Form element value committed (blur after change, or select/checkbox toggle). |
submit |
FormPlugin | Form submission. |
reset |
FormPlugin | Form reset. |
memory |
MemoryConfigGenerator | JS heap snapshot via performance.memory (Chrome-only), polled every 15s. |
user-agent-specific-memory |
MemoryConfigGenerator | Detailed memory breakdown via performance.measureUserAgentSpecificMemory(), polled every 60s. |
<custom> |
track API | Any event sent via betterstack('track', name, data). |
Events
session-start
Source: SessionConfigGenerator (session_config_generator.rb)
Trigger: First event in a new session, or after session timeout. Fired lazily β queued when the first trackable event occurs, not on page load itself. If FingerprintJS is configured, waits for fingerprint resolution (up to 500ms) before sending.
The session is new when there is no existing sid in localStorage, or when the time since last activity exceeds session_timeout_ms.
fingerprint_data is only present when FingerprintJS is enabled; contains raw component data.
No contexts field on this event.
page-load
Source: PageViewPlugin (autocapture-plugins.js)
Trigger: window.load event (fires once per full page load).
Config: Enabled when autocapture_enabled? and autoPageview !== false.
Note: meta.referrer is the browser's document.referrer (the previous page that linked here).
page-change
Source: PageViewPlugin (autocapture-plugins.js)
Trigger: In-app navigation via:
- history.pushState() (SPA routers: React Router, Vue Router, Next.js, Turbo)
- history.replaceState() (only if URL actually changes)
- popstate (browser back/forward)
- hashchange (hash-based routing)
Deduplicated: skipped if URL hasn't changed since last capture.
Config: Same as page-load.
Note: meta.referrer is the previous SPA URL (not document.referrer). The onEventCapture callback in AutocaptureConfigGenerator moves details.referrer β meta.referrer.
page-leave
Source: PageViewPlugin (autocapture-plugins.js)
Trigger: window.beforeunload event (tab close, full navigation away, page refresh).
Config: Same as page-load.
Special behavior: page-leave skips _ensureSessionStarted() β it won't create a new session on its own.
click
Source: TapPlugin (autocapture.js)
Trigger: document.click event on non-touch devices (!('ontouchstart' in window)).
Config: Enabled when autocapture_enabled?.
target.selector is the element tag name. target.attributes contains whitelisted attributes configured in AutocaptureConfigGenerator: value, type, href, src, id, name, placeholder, title, alt, role.
dblclick
Source: TapPlugin (autocapture.js)
Trigger: document.dblclick event on non-touch devices.
Config: Same as click.
Same payload structure as click, but details.type = "dblclick" and payload.event = "click" (the plugin key).
contextmenu
Source: TapPlugin (autocapture.js)
Trigger: document.contextmenu event (right-click). Fires on all devices (no touch guard).
Config: Same as click.
Same payload structure as click, but details.type = "contextmenu".
tap
Source: TapPlugin (autocapture.js)
Trigger: document.touchstart event on touch devices.
Config: Same as click.
Same payload structure as click, but details.type = "tap" and coordinates come from the touch event. Only fires on touch-capable devices.
rage-click
Source: RageClickPlugin (autocapture-plugins.js)
Trigger: 5+ clicks within 8px radius over 2 seconds. Detected by monitoring all document.click events and calculating centroid clustering.
Config: Enabled when autocapture_enabled? AND rage_clicks_enabled?.
After detection, the click buffer is reset.
input
Source: FormPlugin (autocapture.js)
Trigger: document.input event (fires on every keystroke/value change in form elements).
Config: Enabled when autocapture_enabled?.
Note: the value attribute is captured for select elements but the actual typed text in text inputs is NOT captured (only the element attributes are collected via the safelist).
change
Source: FormPlugin (autocapture.js)
Trigger: document.change event (fires when a form element loses focus after its value changed, or on select/checkbox/radio change).
Config: Same as input.
Same structure as input, but details.type = "change". For select elements, target.attributes.value reflects the newly selected value.
submit
Source: FormPlugin (autocapture.js)
Trigger: document.submit event (form submission).
Config: Same as input.
details includes form metadata (action, method, id, name) extracted from target.form.
reset
Source: FormPlugin (autocapture.js)
Trigger: document.reset event (form reset button clicked).
Config: Same as input.
Same structure as submit, but details.type = "reset".
memory
Source: MemoryConfigGenerator (memory_config_generator.rb)
Trigger: Polled every 15 seconds via setInterval. Also fires once immediately on init. Uses performance.memory (Chrome-only, non-standard).
Config: Enabled when memory_enabled?.
No contexts field. Completely different payload structure from autocapture events β no event, timestamp, session, target, or details fields inside payload.
user-agent-specific-memory
Source: MemoryConfigGenerator (memory_config_generator.rb)
Trigger: Polled every 60 seconds via setInterval. Also fires once immediately on init. Uses performance.measureUserAgentSpecificMemory() which requires crossOriginIsolated context (COOP/COEP headers).
Config: Same as memory.
No contexts field. The bytes and breakdown fields come directly from the performance.measureUserAgentSpecificMemory() API result, spread into the payload.
Custom events
Source: betterstack('track', '<name>', <data>) API call
Trigger: Application code calling the track function directly.
Config: Always available once the JS tag is loaded and init'd.
No contexts field. The payload is the raw data object passed to track().
Event flow and filtering
Events pass through betterstack.track() (script_generator.rb:156-184) which applies these filters before queueing:
- Sampling:
session.trackEventsmust be true (determined at session creation byevents_sample_rate) - Analytics events (
page-load,page-leave,page-change): allowed ifcollect_analyticsis enabled, regardless of identified/anonymous settings - Identified events: allowed only if
collect_identifiedis enabled (whenbetterstack._useris set) - Anonymous events: allowed only if
collect_anonymousis enabled (when no user is set)
Special cases:
- session-start and page-leave skip the _ensureSessionStarted() call to avoid infinite recursion / session creation on exit
Plugin β event mapping
| Plugin | Key | Events | Source file |
|---|---|---|---|
TapPlugin |
tap |
click, dblclick, contextmenu, tap |
autocapture.js |
FormPlugin |
form |
input, change, submit, reset |
autocapture.js |
PageViewPlugin |
page |
page-load, page-change, page-leave |
autocapture-plugins.js |
RageClickPlugin |
rage-click |
rage-click |
autocapture-plugins.js |
| (session manager) | β | session-start |
session_config_generator.rb |
| (memory monitor) | β | memory |
memory_config_generator.rb |
| (memory monitor) | β | user-agent-specific-memory |
memory_config_generator.rb |
| (track API) | β | <custom> |
script_generator.rb |
Configuration flags
| Flag | Controls |
|---|---|
autocapture_enabled? |
All autocapture events (click, dblclick, contextmenu, tap, input, change, submit, reset, page-load/change/leave) |
rage_clicks_enabled? |
rage-click event only |
memory_enabled? |
memory and user-agent-specific-memory events |
analytics_enabled? |
Whether page-load/change/leave pass the track filter |
anonymous_events_enabled? |
Whether anonymous user events pass the track filter |
identified_events_enabled? |
Whether identified user events pass the track filter |
autoPageview (user config) |
Whether PageViewPlugin is registered (can be disabled via betterstack('config', { autoPageview: false })) |