Tracking reference
Every signal HLD collects, what produces it, and what it is good for. This is the complete list — if a behaviour is not here, it is not recorded.
The shape of the data
Two levels. A session is one visit, carrying rollups and everything inferred about it. An event is one thing that happened during that visit. Rollups exist so the common questions never have to walk the event stream, and the event stream exists so a visit can be replayed exactly.
text
session ──┬── rollups pageviews, clicks, scroll depth, engaged time
├── acquisition channel, campaign, click id, landing page
├── device & geo browser, OS, viewport, country, network
├── inference intent score, interests, bot verdict
└── events [] the append-only log all of the above derives from
Page and session tracking
| Name | Type | Required | Description |
|---|
| session_start | event | No | First activity in a tab. One per session. |
| pageview | event | No | A page or SPA route was shown. Carries path and title. |
| page_exit | event | No | Leaving a page. Carries dwell time, engaged time and the deepest scroll reached. |
| session_end | event | No | Sent on pagehide via sendBeacon — the only thing that reliably survives unload. |
| visibility | event | No | The tab was hidden and came back. Carries how long it was away, which is what separates engaged time from wall-clock time. |
| idle | event | No | No input for an extended period. |
| resize | event | No | The viewport changed size — relevant because heatmaps are bucketed by viewport. |
Tip:Engaged time, not time on page, is the number worth reading. It excludes gaps with no input at all and time with the tab hidden, so a page left open over lunch does not read as five minutes of attention.
Click and interaction tracking
| Name | Type | Required | Description |
|---|
| click | event | No | An ordinary click. Position is recorded as a fraction of the viewport and a fraction of the full document, so it lines up with the page whatever the screen size. |
| rage_click | event | No | Three or more clicks in the same small area inside one second. Almost always something that looks clickable and is not. |
| dead_click | event | No | A click that hit nothing interactive — no link, button, input or handler within five levels of the DOM. |
| outbound_click | event | No | A link to another host. Carries the destination. |
| download | event | No | A link to a document or archive (pdf, zip, doc, xls, ppt, csv, dmg, exe, pkg). |
| copy | event | No | Text was copied. The text itself is never sent. |
| select | event | No | A selection was made. |
| print | event | No | The print dialog opened. |
| contextmenu | event | No | Right click, with the element description. |
| screenshot | event | No | A suspected screen capture — see below. Carries the key combination and a confidence flag. |
Note:A screenshot cannot be prevented and mostly cannot be seen: the operating system captures the screen without telling the page. What a browser sometimes sees is the keystroke in front of it — PrintScreen reaches the page on Windows, while macOS usually swallows ⌘⇧3/4/5 first, and Win+Shift+S is indistinguishable from ⌘⇧S (Save As), which is why that one is recorded at low confidence. Every count is therefore a floor, not a total: a zero means nothing was detected, not that nothing was taken. Nothing else about the keystroke is kept — the listener sees every key pressed and deliberately records none of them.
Every click carries a description of what it hit — tag, id, first two classes — and the element's visible label. That is what turns a heatmap hotspot into a name. Input values are never read; a label comes from aria-label, a placeholder, or visible text, capped at 120 characters.
Attention and scroll tracking
| Name | Type | Required | Description |
|---|
| pointer sampling | aggregate | No | Mouse position sampled roughly eight times a second, binned in the browser onto a 48×72 grid before it is sent. A five-minute read costs one row per occupied cell rather than one per sample. |
| scroll | event | No | Milestones at 25%, 50%, 75% and 90%. Every scroll event would be thousands of rows per page and would say nothing the milestones do not. |
| scroll reach | aggregate | No | Recorded once per page per session, at the deepest point reached, so the profile counts sessions rather than scroll events. This is what draws the fold line. |
Vertical position is a fraction of the document, not the viewport. A click 20% down a long page is in the same place for everyone; 400 pixels down is not.
Form tracking
| Name | Type | Required | Description |
|---|
| form_start | event | No | First focus into any field of a form. |
| form_field | event | No | A field was focused. Which field — never what was typed into it. |
| form_submit | event | No | The form was submitted. |
| form_abandon | event | No | A form was started and the visitor left without submitting. Derived, not sent by the browser. |
Warning:Field values are never collected, transmitted or stored, and there is no configuration that turns that on. If you need to know what someone entered, that belongs in your own form handler, not here.
Media, search and custom events
| Name | Type | Required | Description |
|---|
| search | event | No | An on-site search. The term is sent only when your own code reports it. |
| video_play / video_progress / video_complete | event | No | Player milestones, when your page reports them. |
| custom | event | No | Anything you name, via hlda("track", name, metadata). Metadata is scalars only, up to ten keys. |
| conversion | event | No | A named conversion with an optional numeric value. Also raised automatically when a visitor reaches one of the site’s configured conversion paths. |
| identify | event | No | Your site told us who the visitor is. Never inferred. |
Performance and errors
| Name | Type | Required | Description |
|---|
| web_vital | session field | No | LCP, CLS, INP and TTFB, kept as the worst value the visitor actually experienced. Reported at the 75th percentile in aggregates, which is how Google grades them — an average hides exactly the tail that fails. |
| error | event | No | Uncaught errors and unhandled promise rejections: message, file and line. Not a replacement for an error tracker, but enough to notice a page that is broken for a fifth of visitors. |
Device, network and location
Collected once per session, on the first batch.
| Name | Type | Required | Description |
|---|
| Browser, OS, device class | server-derived | No | Classified from the user agent on our side, not claimed by the page. |
| Screen, viewport, pixel ratio | browser | No | Also the input to the viewport bucket that heatmaps are grouped by. |
| Language, timezone | browser | No | Reported by the browser. A timezone that disagrees with the IP is one of the bot tells. |
| Connection type, memory, cores | browser | No | Where the browser exposes them. Useful for reading a bad LCP. |
| IP, country, region, city, ASN, network | edge | No | Resolved at the Cloudflare edge from the connection itself — never from the payload. A visitor cannot claim to be somewhere they are not, and attribution built on a claimed country is worse than none. |
| Reverse DNS and organisation | edge | No | One lookup per session. How an anonymous visit from an office network becomes a named account. |
Bot filtering
Sessions are scored on every batch, not just at creation — a scanner looks identical to a reader for the first few hundred milliseconds, and what separates them is whether anything ever happens. Flagged sessions are excluded from every aggregate by default; include_bots=1 puts them back so the flagging itself can be checked rather than trusted.
navigator.webdriver, or a user agent that names itself as automation.- Cloud compute and known scanner networks by ASN — including link-detonation sandboxes, which render pages properly and click.
- A viewport that fills the whole screen at pixel ratio 1: a real desktop browser has window chrome, a headless one does not.
- A browser clock that disagrees with the address's timezone.
Note:Everything except the first two needs two independent tells before it fires. Flagging a real visitor hides the row you wanted to see, so the rules are deliberately conservative in that direction.
What is never collected
- Keystrokes, form field values, or the contents of anything typed.
- Page text, screenshots, or session video replay.
- Cookies of any kind, or any cross-site identifier. The visitor id is one random string in
localStorage, readable only by the site that set it. - Anything from a browser sending Do Not Track, when the site is configured to honour it.