Sessions & visitors
Individual visits, and one visit replayed step by step. Requires the analytics:sessions scope.
List visits
bash
GET /v1/analytics/sessions?days=7&intent=hot&limit=100| Name | Type | Required | Description |
|---|---|---|---|
| intent | cold | warm | hot | No | Filter by inferred intent band. |
| channel | string | No | Filter by acquisition channel. |
| identified | 0 | 1 | No | Only visits where your site called identify(). Never inferred from an address. |
| converted | 0 | 1 | No | Only visits that converted. |
| limit | integer | No | 1–500, default 100. Ordered by most recent activity. |
What a session carries
| Name | Type | Required | Description |
|---|---|---|---|
| session_key | string | No | One per browser tab session. Pass it back to replay the visit. |
| visitor_id / visit_number | string / integer | No | A random id in the visitor’s own localStorage, and which visit this is. The count is done server-side — a cleared localStorage would otherwise reset it to 1 forever. |
| channel / channel_reason | string | No | The attribution, and what decided it. |
| utm_* / click_id_type / referrer_host | string | No | The campaign parameters the visit landed with. |
| landing_path / exit_path | string | No | Where the visit started and ended. |
| browser / os / device_type / viewport_* | string | No | device_type is the viewport bucket heatmaps are grouped by. |
| country_name / city / network_org / ip_company | string | No | Resolved at the edge. ip_company is the reverse-DNS organisation. |
| pageviews / click_count / max_scroll_pct | integer | No | Engagement rollups. |
| active_ms / dwell_ms | integer | No | Engaged time, and wall-clock time. Read the first one. |
| form_start_count / form_submit_count | integer | No | The abandonment gap, per visit. |
| bounced / converted / conversion_value | boolean / number | No | See Reports for how a bounce is defined here. |
| intent_score / intent_band / inferred_interests | number / string / string[] | No | See Marketing inference. |
| identified_email / identified_name / identified_company | string | No | From identify() calls only. Null unless the key holds analytics:visitors. |
| is_bot / bot_reason | boolean / string | No | Excluded by default; include_bots=1 returns them with the reason they were flagged. |
| lcp_ms / inp_ms / cls_x1000 / ttfb_ms | integer | No | The worst value this visitor actually experienced. |
Replay one visit
bash
GET /v1/analytics/sessions?session=aB3xY7…Returns the session plus its events in order, up to 1000. This is the whole visit: every pageview, click, scroll milestone, form interaction and exit, with timing.
json
{
"data": {
"session": { "session_key": "aB3xY7…", "channel": "paid_search", … },
"events": [
{ "event_type": "pageview", "path": "/pricing", "page_title": "Pricing",
"occurred_at": "2026-09-04T02:11:04.221Z" },
{ "event_type": "scroll", "path": "/pricing", "scroll_pct": 50,
"occurred_at": "2026-09-04T02:11:19.880Z" },
{ "event_type": "rage_click", "path": "/pricing", "x_ratio": 0.47,
"doc_y_ratio": 0.62, "target": "div.plan-card",
"target_text": "Contact sales", "occurred_at": "2026-09-04T02:11:31.004Z" },
{ "event_type": "page_exit", "path": "/pricing", "dwell_ms": 74210,
"active_ms": 41880, "scroll_pct": 78,
"occurred_at": "2026-09-04T02:12:18.431Z" }
]
}
}Visitor identity and the scope split
Without analytics:visitors, the three identity fields come back null rather than the request failing. That is what lets a key be handed to a reporting dashboard or an outside contractor without also handing over an email list — the aggregates still work, the export is simply not personally identifying.
Warning:The rows are your visitors on your site, so this is a blast-radius control rather than a privacy boundary. Issue the narrower key where you can.