Getting started
How Recording Works
What the AnyReplay recorder captures: DOM snapshots and mutations, chunked uploads, masking before data leaves the page, and replay inside a sandbox.
AnyReplay does not record video. On the web it records the page itself — its structure and every change to it — and rebuilds the page in the dashboard when you press play. On React Native it records the element tree React committed. This page explains the web recorder; the mobile differences are at the end.
Snapshots and mutations
When recording starts, the browser SDK takes a full snapshot: a serialised copy of the DOM, with styles and attribute values. From then on it records incremental events: nodes added and removed, text and attributes changed, mouse movement, clicks, scrolling, input and viewport resizes. Each event carries a timestamp, so playback can reproduce the timing. The recording engine is rrweb, bundled inside the SDK.
Every page load begins with a new full snapshot. A reload or a same-origin navigation within 30 minutes of activity continues the same session — the id and page count are kept in sessionStorage — so a journey across pages replays as one recording. After 30 minutes of inactivity the next page starts a new session.
What is added on top
- Route changes. In a single-page app the recorder notices
pushState,replaceStateandpopstateand records a$navigatemarker with the new URL and title. See single-page apps. - Custom events.
track(name, properties)puts a named marker on the timeline. See custom events. - Signals. Uncaught errors and unhandled promise rejections flag the session as having an error; three or more clicks within a second in nearly the same spot flag a rage click. Both can be filtered on in the session list.
- Session details. The first chunk carries the start time, URL, browser language, user agent, viewport size and referrer.
Chunks and delivery
Events are buffered in the page and sent to the ingest service in numbered chunks: when 200 events have accumulated or every 5 seconds, whichever comes first. Requests are sent without cookies. When the tab is hidden or the page is closing, the remainder is handed to navigator.sendBeacon, which the browser delivers after the page is gone, so the end of a session survives the tab closing.
Ingest is idempotent by chunk number: a retried chunk is recognised and not stored twice. Network errors, 429 and 5xx responses are retried, keeping a bounded buffer. The recorder never gives up on a network that is merely away: it retries after 2 s, doubling to a minute (never before a Retry-After), and sends a backlog in chunks of about 256 KB. (Before 0.2.0 it stopped after five failures in a row.) A refusal such as 402 or 403 is a final answer and recording stops immediately. The codes are listed in ingest responses.
Masking happens in the page
Masking is applied while events are serialised, before anything is sent. A masked input value becomes asterisks in the payload; the original characters never reach AnyReplay. Form field values are masked by default; maskAllInputs: false records what visitors type, except passwords, payment fields and values shaped like a card number, which are always masked. Text typed into a rich-text editor is recorded unless you set maskAllTyping: true. Elements with the ar-block class are recorded as an empty placeholder of the same size, and elements with ar-mask keep their layout but lose their text — on a field, their value too. <script> contents are never recorded. Details and examples are in masking and blocking.
Sandboxed replay
Replaying a recording means rebuilding somebody else's HTML inside the dashboard, so the player treats it as untrusted:
- Script bodies were replaced at record time and never left the recorded page.
- Script elements are rebuilt as inert
noscriptelements, so markup cannot execute on replay. - The replay iframe is sandboxed without
allow-scripts. A test in the dashboard fails the build if that permission is ever enabled.
Translation works on the recording
Because the recording is text and structure rather than pixels, the dashboard can extract the visible strings, translate them and substitute them before the player rebuilds the page. Masked values are already asterisks by then, so they are never translated. See session translation.
On React Native
React Native has no DOM. The mobile SDK walks React's committed fiber tree on a timer (every 500 ms by default), measures each element through Fabric, and records what changed since the last tick — element types, text, geometry and a few visual properties. An idle screen sends nothing. The result replays as a faithful wireframe rather than a screenshot. See React Native.