Session recording
See your site through your visitors' eyes. Mouse movements, clicks, scrolls and DOM mutations are recorded as space-efficient rrweb events and replayed in a built-in player — fully cookieless with automatic privacy masking of sensitive fields. Business plan (EUR 29/month) and above.
# How to enable recording
Override via HTML attribute (fallback)
If you prefer to pin tracker config in HTML (e.g. multiple sub-domains share the same site ID but only one should record), the data-record="1" attribute on the script tag overrides the server config:
<script defer src="https://api.xictraq.com/t.js"
data-site="YOUR_SITE_ID"
data-record="1"></script>
<noscript><img src="https://api.xictraq.com/api/px?s=YOUR_SITE_ID" alt="" width="1" height="1" style="position:absolute;left:-9999px" referrerpolicy="no-referrer-when-downgrade"></noscript> We recommend the server configuration as the default — it is live-adjustable and applies instantly. There is no JavaScript variable like cfg.rec — configuration runs exclusively via the Settings tab or data-* attributes.
# Recording player
# Features
rrweb-based (open source)
Instead of capturing image frames (heavy and privacy-questionable), rrweb records DOM mutations + mouse events — typical storage: 2–8 KB per second. The entire recording is replayed in the browser, the real HTML/CSS stack of the site is visible.
Privacy by default
Masking applies in three layers, all at the tracker — sensitive data never even leaves the visitor browser in clear text:
maskAllInputs— all input fields are masked by default; typed values never reach the recording.- auto-redaction in text nodes: credit-card numbers (13–19 digits, Luhn-checked) and IBANs are automatically replaced with • — even when they appear as plain text on confirmation or account pages. Deliberately conservative so ordinary numbers/IDs survive.
- opt-in masking: regions marked with data-xictraq-mask or custom CSS selectors (tracker settings) are fully masked. data-xictraq-block excludes an element from recording entirely (blockSelector).
Auto-tagging: rage clicks, dead clicks, errors
A cron (/cron/tag-recordings) analyses every completed recording via heuristic and attaches tags (session_recordings.tags column, JSON array):
rage_click— 3+ clicks within 2 s in a 30 px radius of the first clickdead_click— click without DOM mutation and without page change within 1.5 s (broken buttons / broken onclick)error— window.onerror or unhandledrejection during the session — tracker writes it as rrweb custom event into the recording stream so the cron can find it
Tags appear as badges in the recordings list at Analytics → Recordings & Tests.
Linked to form events
Form events and recordings carry the same daily identifier of the visit (session_hash); this lets you match them to each other. There is no shared recording ID: the recording identifier is only sent with the recording chunks to /api/p/r. The recording list shows problematic sessions directly via the auto-tags. Freely configurable SQL-style filters (“sessions with form view without submit” etc.) are not yet self-service — on request we set up custom queries for you.
First-party hosting (no 3rd-party CDN)
The rrweb engine and player CSS are NOT loaded from the rrweb CDN, but from the API origin (api.xictraq.com or your first-party proxy) with obfuscated filenames (rx.js, rxp.js, rxp.css). Standard EasyPrivacy filterlists would block “rrweb.min.js” by filename — our variant goes undetected.
Consent-gated start (no auto-recording)
Even when recording is enabled in the settings, capture does NOT start automatically on load. It waits for the consent signal from your page or consent tool:
xictraq.consent('granted'); // startet Recording (wenn aktiviert)
xictraq.consent('denied'); // stoppt Recording
xictraq.record('start'); // Recording gezielt ein-/ausschalten
xictraq.record('stop'); Only when both activation AND consent are present does the rrweb engine (rx.js) load and capture begin. The recording ID lives in the tab sessionStorage and applies per recording: after 30 minutes without a recorded event (changes to the page count as well) and with the first page load after midnight (UTC), a new recording begins with a new recording ID (from tracker version 61). No cookie; sessionStorage is bound to the tab and the website.
Chunk transport & crash-safe flushing
rrweb events are buffered and sent in chunks to /api/p/r — throttled so even long sessions stay lean:
- flush once 60 events are buffered, plus every 10 seconds, plus on pagehide (final chunk; it is omitted after more than 30 minutes without a recorded event) and when the tab goes to the background.
- sampling: mouse moves every 100 ms, scroll every 150 ms, inputs as last value only — cuts volume without losing replay fidelity.
- server-side cap: a single recording file is capped at 10 MB so outliers cannot flood disk. Once the cap is reached, no further recording begins in that tab, not even after a pause or a change of day.
- external stylesheets are inlined into the rrweb snapshot at ingest (same-host only, SSRF-safe) — so replay stays visually correct even after the site redeploys with newly hashed asset URLs.
Storage & retention
Sessions with no new chunk for 30 minutes are marked complete by /cron/compress-recordings (catches browser crashes, abrupt tab closes and recordings after the idle period, for which no pagehide flush arrives). Completed sessions older than one hour are compressed by the same cron to .ndjson.gz (~70 % space saved, max 200 per run). Sample rate is configured by you in Analytics → Settings (1–100 %, applies to all tracker features). For privacy reasons (Art. 5(1)(e) GDPR, storage limitation) recordings have a fixed cap of 90 days — independent of plan and decoupled from the otherwise unlimited aggregate analytics retention. If your plan analytics retention is shorter than 90 days, that shorter window applies. The "Extended data retention" add-on extends aggregate analytics retention but does NOT lift the 90-day cap for recordings.