Explore documentation
JavaScript tag events
Complete reference of every web event generated by the JavaScript tag.
Basic event structure
Every event 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
Shared payload.meta for autocapture events
All autocapture events such as click, dblclick, contextmenu, tap, input, change, submit, reset, page-load, page-change, page-leave, rage-click include this meta block in payload:
Tracking custom events
Created with the betterstack('track', '<name>', <data>) API call.
Events
| Event | Description |
|---|---|
session-start |
Marks the beginning of a new session. Includes UTM params, referrer, and fingerprint data. |
page-load |
Initial full page load (window.load). |
page-change |
In-app SPA navigation (pushState, replaceState, popstate, hashchange). |
page-leave |
Tab close or full navigation away (beforeunload). |
click |
Left-click on non-touch devices. |
dblclick |
Double-click on non-touch devices. |
contextmenu |
Right-click (all devices). |
tap |
Touch start on touch devices. |
rage-click |
5+ clicks within 8px / 2s — indicates user frustration. |
input |
Keystroke or value change in a form element. |
change |
Form element value committed (blur after change, or select/checkbox toggle). |
submit |
Form submission. |
reset |
Form reset. |
memory |
JS heap snapshot via performance.memory (Chrome-only), polled every 15s. |
user-agent-specific-memory |
Detailed memory breakdown via performance.measureUserAgentSpecificMemory(), polled every 60s. |
<custom> |
Any event sent via betterstack('track', name, data). |
session-start
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 fingerprinting 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 fingerprinting is enabled; contains raw component data.
page-load
window.load event (fires once per full page load). Enabled when autocapture_enabled? and autoPageview !== false.
Note: meta.referrer is the browser's document.referrer (the previous page that linked here).
page-change
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.
Note: meta.referrer is the previous SPA URL, not document.referrer. The onEventCapture callback in AutocaptureConfigGenerator moves details.referrer → meta.referrer.
page-leave
window.beforeunload event: tab close, full navigation away, page refresh.
Special behavior: page-leave skips _ensureSessionStarted(): it won't create a new session on its own.
click
document.click event on non-touch devices (!('ontouchstart' in window)). 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
document.dblclick event on non-touch devices.
Same payload structure as click, but details.type = "dblclick" and payload.event = "click".
contextmenu
document.contextmenu event, right-click. Fires on all devices. no touch guard.
Same payload structure as click, but details.type = "contextmenu".
tap
document.touchstart event on touch devices.
Same payload structure as click, but details.type = "tap" and coordinates come from the touch event. Only fires on touch-capable devices.
rage-click
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
document.input event: fires on every keystroke/value change in form elements.
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
document.change event:fires when a form element loses focus after its value changed, or on select/checkbox/radio change.
Same structure as input, but details.type = "change". For select elements, target.attributes.value reflects the newly selected value.
submit
document.submit event: form submission.
details includes form metadata such as action, method, id, name extracted from target.form.
reset
document.reset event, when form reset button clicked.
Same structure as submit, but details.type = "reset".
memory
Polled every 15 seconds via setInterval. Also fires once immediately on init. Uses performance.memory (Chrome-only, non-standard).
No contexts field. Completely different payload structure from autocapture events: no event, timestamp, session, target, or details fields inside payload.
user-agent-specific-memory
Polled every 60 seconds via setInterval. Also fires once immediately on init. Uses performance.measureUserAgentSpecificMemory() which requires crossOriginIsolated context (COOP/COEP headers).
No contexts field. The bytes and breakdown fields come directly from the performance.measureUserAgentSpecificMemory() API result, spread into the payload.
Need help integrating the JavaScript tag?
We're here for you! Let us know at hello@betterstack.com and we'll be happy to help.