Turning on recordings
A recording rebuilds one visit in the dashboard: the page structure as the visitor saw it, scrolling, clicks and page changes – with every input and text masked in the browser before anything leaves the device. Visits without a recording can still be replayed as a reconstruction („Rekonstruktion“) from the cookieless signals on the page snapshot; the player labels which of the two you are watching.
The wizard
Einstellungen › Aufnahmen & Heatmaps › Aufnahmen einschalten walks through five steps
(deep link ?step=banner|vorschau|ausschluss|menge|fertig):
- Banner prüfen: X3 checks your consent banner (
POST …/behavior/cmp-check, a background run with visible progress) and shows the setup for the detected banner – see Consent banners. Cookiebot only knows categories; there you confirm that the category text names session recording, and X3 stores that confirmation with the text it read. Recording can only be switched on once this step is green or confirmed. - Datenschutz-Vorschau: your page next to what ends up in a recording; unmask single elements or exclude a page from here.
- Ausschlüsse: page patterns, query parameters and elements that are never recorded.
- Wie viel: which visits are kept (see below), daily caps, storage period, linking recordings to leads and the optional AI summaries.
- Fertig: a summary, the generated banner purpose and privacy-policy block, and a live check whether the first recording arrives.
The recording level itself is set in Datenschutz & Erfassung („Nur mit Zustimmung“ by default; red levels need an admin acknowledgement).
GET /v1/projects/{project}/behavior/setup returns the same diagnostics: traffic and consent of the
last days, the first recording, SDK and proxy version, caps and the banner check.
What is kept
The SDK records consented visits into a short buffer; the server keeps a recording only when it is worth watching („Smart“ sampling) and deletes the rest after 48 hours at the latest (the decision falls 18–22 hours after the last packet, so late conversions such as a confirmed WhatsApp lead still count):
| Reason | Kept when |
|---|---|
converted, lead | the visit reached a goal or became a lead |
hot | interest score at or above the project's „Heiß“ threshold (default 60) |
friction | rage clicks, dead clicks, U-turns or an abandoned form |
random | a random share (default 20 %) as an honest sample |
watch | someone watched the visit live |
Caps per day (maxPerDay, maxBytesPerDay) protect storage; reaching one opens the alert
recordings_cap_reached. Storage period: 7, 30 (default) or 90 days; saved clips („Ausschnitt
merken“, with a reason) at most 90 days.
Masking
Masking happens in the visitor's browser before anything leaves the device, and the server checks
every packet again. Einstellungen › Aufnahmen & Heatmaps › Maskierung decides per category what
is readable in recordings (API PATCH /v1/projects/{project}/settings/behavior → recordings.mask,
MCP behavior_masking_get / behavior_masking_update):
Category (key) | Options, strictest first | X3 recommendation |
|---|---|---|
Page texts (text) | shape („Xxxxx xxx“) · pii (visible, e-mail/phone/IBAN/card number/postcode + town removed) · visible | marketing sites pii, sector presets shape |
Form inputs (inputs) | masked (never, not even the length; only „field edited“) · pii (final value per field, PII removed) · visible (final value) | masked |
Choices & quiz answers (choices) | masked (which answer was picked is never stored; answer texts follow page texts, shapes under shape) · visible | masked |
Attributes (attributes: alt, title, placeholder, aria-label, data-*) | shape · pii · visible | like page texts |
Links & query parameters (links) | scrubbed (mailto/tel masked, query except utm_*/click ids removed, ids/tokens in paths → :id) · pii (complete, PII removed) · visible | scrubbed |
Images (images) | placeholder (grey box of the same size) · visible | visible |
Every option shows a risk light (green/yellow/red) with a one-sentence reason. An option less strict
than the recommendation needs the acknowledgement of a project admin (name, time, optional reason),
stored with the settings and in the audit log (behavior.mask.ack); stricter options never do.
Settings stored before masking became a setting keep exactly their behaviour (profile: "strict" →
shape, "balanced" → pii; the other categories as before).
Only for test and internal visits (relax: "test"): the relaxed values apply only to visits your
site marks itself with test: true in the snippet (data-test on the script tag – e.g. for signed-in
staff) and to devices marked with the dashboard's signed link Gerät als intern markieren (see
SDK reference › Internal devices; such devices count as test traffic
everywhere). The test parameter (?x3_test=1 or the project's own) and a bare ?x3_internal=1 count the
page load as test traffic but never relax the masking: anyone can put them on a link. Every other visit
gets the stricter of your choice and the X3 recommendation, and only then are test visits recorded at
all (otherwise test traffic captures nothing). The server applies its own view of the policy: a packet
that claims to be a test session while the project does not relax for tests gets the ordinary policy.
Own selectors: unmaskSelectors are readable (PII filtered) while page texts are shape;
maskSelectors are always shapes (like address and [data-x3-mask]); blockSelectors are not
recorded at all and replaced by a grey box (like [data-x3-block], iframes, canvas, video).
Never switchable: passwords, payment fields (autocomplete="cc-*"), one-time codes, hidden and
file inputs, editable areas (contenteditable), keystrokes, network, console, cookies and clipboard –
under every option, also for test visits. The health preset locks every relaxation (Art. 9 GDPR).
Changes are versioned (recordings.mask.version, stored per recording) and reach the websites with the
SDK's next config fetch – no redeploy of the site. They apply to new recordings; a stricter rule also
re-masks stored recordings in a visible run (texts, attributes, input values, choice state, links).
Pages matching the exclusion list (login, account, checkout, payment, password reset, admin – and under
the health preset appointments, patient forms and quizzes) are never recorded.
Watching
Sitzungen is one list of every visit (one list):
the playlists („Heiß ohne Anfrage“, „Abbruch im Quiz“, „Wutklicks“, „WhatsApp ohne Lead“,
„Angefragt“, own playlists) filter the table, and ▶ plays a visit – its recording when there is one,
otherwise the reconstruction from clicks, scrolling and page changes; only the player says which.
Visits that can be neither played nor reconstructed have no ▶. Opening a recording needs the scope
recordings:read (without it the visit plays as a reconstruction), plays from a sandboxed stage
origin through a 60-second signed link and writes an audit row (recording.view). How long
recordings are kept is set under Einstellungen › Aufnahmen & Heatmaps. Old links with ?rec=1 or ?rec=0
redirect to the list with the same filters.
Vollbild. On a visit, „Vollbild“ (or the key F) opens the same player over the whole window –
no second page, the playback continues where it was: large stage, timeline with markers for clicks,
page changes, quiz steps, form submits and rage clicks, the event list next to it (a click jumps
there), speed 1×/2×/4×/8× and „Inaktivität überspringen“ (pauses of 3 s or more). Keys: Space
play/pause, ←/→ 5 s, P/N previous/next event, 1/2/4/8 speed, S skip inactivity, F Vollbild, Esc
closes, ? lists them. The address gets ?fullscreen=1, so a copied link opens in Vollbild.
Playback in apps (stage links)
Apps that cannot embed the dashboard's iframe – the X3 App on iOS and Android – ask for the same signed links as JSON:
GET /v1/projects/{project}/recordings/{id}/stage-link?host=native(scoperecordings:read, audited asrecording.viewlike the 302 of…/recordings/{id}/data)GET /v1/projects/{project}/snapshots/{id}/stage-link?host=native(page images and heatmaps, scopeanalytics:read; page images taken from recordings also needrecordings:read)
The answer has url (a 60-second document on the stage origin for a top-level WebView), data
(the 60-second link of the recording or snapshot that the stage loads itself), assets (images,
fonts and stylesheets of the view, 10 minutes), expiresAt, startedAt and, for snapshots, the
capture viewport. The host is part of the link's signature: a native link opens only the
WebView document (never framed, frame-ancestors 'none'), a frame link only what the
dashboard's iframe needs. The stage talks to the WebView through
window.ReactNativeWebView.postMessage (JSON strings) and listens on window.__x3StageReceive;
the messages are the same as in the dashboard (replay.load, replay.cmd, load-snapshot,
map.scan) plus heatmap.paint / heatmap.clear, with which the stage paints a heatmap layer
itself. When the stage reports expired assets, the app asks for a new stage link. Support views
cannot open recordings.stageLink (like recordings.data); snapshots.stageLink stays readable
there.
Sharing a recording
„Link teilen“ on a recording creates a view-only link without login, for example for a client:
- Only this recording, masked exactly as it was recorded (the masking can never be relaxed for a link), no visitor identity, no contact or lead data, no attribution – on a minimal X3 page with „Bereitgestellt mit X3“.
- Expiry 1, 7 or 30 days or unlimited (default 7 days), an optional password (8+ characters, send it separately), revocable at any time („Widerrufen“; final). Each link shows its views and the last view.
- The recording is kept as long as the link lives (at most 90 days, „Merken“ with the reason „Geteilt per Link“) so the link does not break when the recording would otherwise expire.
- Needs
recordings:readandproject:admin. Under the health preset recordings cannot be shared, and links created before the switch stop working. - Every created and revoked link and every view of the page is in the audit log (
recording_share.created,recording_share.revoked,recording.viewwith channelshare). The public route is rate-limited per link and visitor. Details of the endpoints: share links.
Claude does the same with the MCP tools recordings_share_create, recordings_share_list and
recordings_share_revoke (the link is shown once).
Summaries with your own Anthropic key (optional)
X3 can write one sentence per visit („Satz zum Besuch“) with the likely reason there was no enquiry. It is off by default and uses your organisation's own Anthropic API key; X3 never sends customer data with a key of its own.
- Kunden & Team › KI-Apps › Anthropic-Schlüssel: an organisation admin enters the key. X3 checks it with a test call before saving, stores it encrypted, shows only a masked hint and writes an audit row. Model (default Claude Sonnet 5) and a monthly token cap are set there; a meter shows this month's usage per project.
- Einstellungen › Aufnahmen & Heatmaps, wizard step „Wie viel“: switch on the summaries per project (disabled with an explanation while the organisation has no key or the health preset is on). The run state with „Jetzt zusammenfassen“ is shown on the same page.
The job behavior.ai.summarize runs every 10 minutes (or at once with „Jetzt zusammenfassen“). Its
only input is the masked semantic visit log (the same text MCP behavior_visit_log returns) – never inputs,
DOM or video. Visits without consent are only summarised when the organisation switched on
„Einzelbesuche an KI-Apps geben“. The run state is visible: waiting, running with progress, done, or
an explanation with retry – key rejected (enter a new one), rate limit or overload (retried with
back-off), cap reached (continues next month or after raising the cap). The health preset blocks
summaries. When a visit is deleted, its summary is deleted with it.
Deleting
- One recording:
DELETE /v1/projects/{project}/recordings/{id}(project:admin). - Sessions, a visitor, a lead or a page and range:
POST …/recordings/erase– a background run with progress and a receipt in the audit log; it removes recordings, clips, heat facts and summaries. - Visitors delete their own data with the privacy center.
Operations
Recordings need an object store and a stage origin on its own registrable domain; the variables
are listed in Environment variables. Locally the fs driver and
the API host as stage are enough. For tests and local development X3_ANTHROPIC_BASE_URL points the
summary job at a mock server and X3_ANTHROPIC_TIMEOUT_MS shortens its timeout; both are ignored in
production.