Session Replay
Visual playback of visitor sessions showing cursor movement, clicks, scroll behavior, and page navigation — all from the R2 event logs captured by tracker.js.
Per-site recording control
Session (rrweb) recording is configurable per site. When the tracker is initialised with a site key (PulseGate.init({ siteKey, ... })), it calls GET /track/config?siteKey=... after session start. Only if the response has recordSession: true does it load rrweb and send recording batches to /track/recording. The same domain rules as form config apply (Origin/Referer must match an allowed domain for that site). You can turn recording on or off in Forms config → expand a site → Record session (replay). Sessions and behavioral events are always stored; only the DOM recording (replay) is conditional. Embeds that do not pass siteKey keep the previous behaviour (recording on for all).
How It Works
The tracker script (/tracker.js) captures behavioral events in real-time:
| Event Type | Data Captured |
|---|---|
mousemove | x, y coordinates (throttled 100ms) |
click | x, y, element (tag + id + class) |
scroll | scroll_percent (0-100, throttled 250ms) |
page_view | page URL |
navigation | SPA route changes |
visibility_change | tab focus/blur |
Events are batched every 5 seconds and stored as append-only R2 objects under sessions/YYYY/MM/DD/{session_id}/events/.
The replay viewer reads these events back and plays them chronologically on a visual canvas.
API Endpoints
All data endpoints require API key authentication (same key as /analytics/*).
GET /replay
Serves the self-contained HTML replay viewer. No auth required — the viewer itself is public; data fetching from within the viewer uses the API key entered by the user.
GET /replay/sessions
Lists sessions with event counts. Supports sorting and filtering.
Query Parameters:
| Param | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Max results (capped at 100) |
offset | number | 0 | Pagination offset |
visitor_id | string | — | Filter by visitor ID |
sort | string | started_at_desc | Sort order: started_at_desc, started_at_asc, duration_desc, duration_asc, engagement_score_desc, engagement_score_asc, event_count_desc, event_count_asc |
entry_page | string | — | Filter by entry page URL (substring match) |
country | string | — | Filter by country code (exact) |
date_from | string or number | — | Filter sessions started on or after this date (YYYY-MM-DD or timestamp ms) |
date_to | string or number | — | Filter sessions started on or before this date (YYYY-MM-DD or timestamp ms) |
Response:
{
"sessions": [
{
"session_id": "abc-123",
"visitor_id": "def-456",
"entry_page": "https://example.com/",
"country": "IN",
"started_at": 1708617600000,
"duration": 300000,
"engagement_score": 65,
"event_count": 142
}
],
"total": 1
}GET /replay/sessions/:id
Returns full session metadata and all events for playback.
Events are loaded from R2 first (append-only event files). Falls back to D1 events table if R2 has no data.
Response:
{
"session": { "...full SessionRecord..." },
"events": [
{
"event_id": "evt-1",
"event_type": "click",
"x": 450,
"y": 320,
"element": "BUTTON#cta.hero-btn",
"page": "https://example.com/",
"timestamp": 1708617612000
}
],
"event_count": 142
}Viewer Features
The HTML viewer at /replay includes:
- Session sidebar — searchable list with engagement scores, country, event count, duration
- Visual canvas — shows cursor movement trail, click pulse animations, scroll position indicator, current page URL
- Timeline — scrubber bar with event type ticks (red = clicks, green = scroll, yellow = page views), elapsed/total time
- Playback controls — play/pause, 1×/2×/4×/8× speed
- Keyboard shortcuts — Space (play/pause), arrow keys (skip ±5s), 1-4 (speed)
- Visitor filter — search by visitor_id to focus on a specific user's sessions