The SDK keeps a rolling window of the DOM in memory. When a report is filed that window is frozen and attached; the rest is discarded. Nothing is uploaded unless someone files a report.
Turning it on
Replay is server-gated — enable it for the app in the dashboard, and the SDK
picks it up from GET /api/config on the next start.
Locally you can only turn it off:
init({ apiKey: 'txx_live_…', sessionReplay: { disabled: true } });
samplingRate on the server is the fraction of sessions that buffer at all. At
0.1, nine in ten sessions never allocate the buffer — which is how you keep the
memory cost off most users while still getting replays.
Format
Web replays are rrweb, attached with kind: "session-replay" and
format: "rrweb". A player dispatches on format rather than sniffing bytes;
the native SDKs emit traceitx-vtree-v1 instead, and both share the report’s
epoch-ms clock so replay frames align with
breadcrumbs.
rrweb records the DOM, not the screen — so a replay reproduces whatever the browser can rebuild from markup and stylesheets. Canvas contents, cross-origin iframes and video frames are not in it.
Privacy
Elements marked sensitive are blocked in the recording — rrweb never serialises their subtree, so the content never enters the buffer, let alone the upload. See Sensitive content.
Text redaction rules are not applied to the replay stream in the current release: the recorder captures text and input values as rendered. A secret that appears on screen must be marked sensitive; a redaction rule alone will not keep it out of the replay.
Cost
The buffer holds a serialised DOM diff stream, not video, so it is measured in
tens of kilobytes rather than megabytes. rrweb itself is in a lazy chunk and is
fetched only once replay actually starts, so an app with replay off never pays
for it. The practical limit is memory on long-lived sessions;
replayDurationSec on the server bounds the window.