What Session Replay Actually Records (and What It Doesn't)
Session replay is a recording of a user’s visit to your web app that you can play back like a video. But if you’re asking “what is session replay” as an engineer rather than a marketer, the accurate answer is more specific and more useful: it’s a serialized snapshot of the DOM plus a timestamped stream of mutations, inputs, and scroll positions, reconstructed later in a sandboxed player. No pixels are captured. There is no video file.
That one architectural fact explains almost everything about what replay can and can’t show you.
What is session replay, mechanically
When a recording script initializes on a page, it does two things.
First, it takes a full snapshot of the current DOM — every element, attribute, and text node — and serializes it to JSON. Stylesheets get inlined or referenced so the player can re-render the page faithfully.
Second, it registers a MutationObserver (see the MDN documentation) plus listeners for input, mouse movement, scroll, and viewport resize. From then on, it doesn’t re-capture the page; it records diffs. A node was added here, an attribute changed there, the user typed into this field, the viewport scrolled 340 pixels. Each event gets a timestamp.
Playback is the reverse: the player rebuilds the initial snapshot inside a sandboxed iframe, then applies the mutation stream on a timer. What you’re watching is your own app being re-rendered, not footage of the user’s screen.
This design is why replay data is surprisingly small — typically hundreds of kilobytes for a multi-minute session, versus tens of megabytes for actual screen video — and why it can capture things video never could, like the exact input value in a field or the precise DOM node under a rage click. If you want the full pipeline from MutationObserver to player, I’ve written up how session replay works under the hood separately.
What gets captured
The dependable list, common to every DOM-based recorder I’ve used:
- The full DOM structure and its evolution over time
- CSS, either inlined at snapshot time or fetched by the player
- Mouse movement, clicks, and touch events with coordinates
- Scroll positions per scrollable element
- Input values — usually masked by default for sensitive types, but capable of recording keystrokes into any field
- Viewport size and resizes
- Page navigations within the same app
Most engineering-oriented tools bolt three more streams onto the same timeline: console output, network request metadata, and JavaScript errors. Those aren’t DOM recording at all — they’re separate instrumentation that shares timestamps with the replay — but in practice they’re the reason replay is useful for debugging rather than just for watching users get lost.
What’s invisible
Here’s the part vendor pages skip. Because the recorder lives inside your page’s JavaScript context and reads the DOM, anything outside that context simply does not exist to it.
Cross-origin iframes. The browser’s same-origin policy blocks your script from reading into an iframe served from another domain. Your Stripe payment element, your Intercom widget, embedded YouTube — in the replay these render as blank boxes. This is a feature for payment iframes (it’s a large part of why they exist) and an annoyance for everything else.
Canvas and WebGL, by default. A <canvas> element is a bitmap; the DOM only knows a canvas exists, not what’s drawn on it. Recorders can optionally sample canvases into images, but it’s expensive and off by default. If your app is a charting dashboard or a design tool, stock replay shows an empty rectangle where your product is.
Anything the browser draws itself. Native <select> dropdown lists while open, date pickers, autofill suggestion menus, basic-auth prompts, print previews, permission dialogs, the file-upload chooser. These are OS or browser chrome, not DOM.
Other tabs, other apps, the user’s screen. Replay is scoped to your document. If the user switched to their email for two minutes, you see a gap — you cannot see where they went. Good.
The user’s actual rendering. The player re-renders your DOM in your browser with your fonts and extensions. A layout bug caused by an aggressive ad blocker’s cosmetic filters, a missing font on the user’s machine, or a browser zoom quirk may not reproduce visually in the replay, even though the DOM events are all faithfully there. This has burned me more than once: the replay looked fine while the user was staring at overlapping text.
Video and audio playback state, beyond the element existing and its attribute changes.
The privacy consequences
DOM recording sits in an odd spot: less invasive than screen capture in some ways, more invasive in others.
Less invasive because the boundaries are structural. Cross-origin payment fields are unreadable by construction, other tabs don’t exist, and there’s no bitmap that might accidentally include a notification popping over the page.
More invasive because the recorder sees data, not pixels. A screen recording of a password field shows dots. A naive DOM recorder captures the actual value attribute — which is why every serious tool masks input[type=password] unconditionally and defaults to masking all inputs. But defaults only cover inputs. Text nodes — the rendered account page showing a user’s email, address, and last four card digits — are visible unless you explicitly mask them. Masking is a configuration exercise you own, and treating vendor defaults as sufficient is how PII ends up in your replay storage. That’s a compliance problem under GDPR and similar regimes, and it deserves its own checklist.
The honest privacy framing: session replay records what your app rendered and what the user did inside it, at data-level fidelity. It does not record their screen. Both halves of that sentence matter.
The debugging consequences
For debugging, DOM recording beats video, and it isn’t close.
You can inspect the replay like a live page: what class was on that button, what the DOM looked like the instant before the error, which element actually received the click. Paired with the console and network streams, you can watch a user hit a failure and read the stack trace and the 500 response that caused it on the same timeline. Video gives you none of that — you’d be squinting at pixels trying to guess what state the app was in.
The blind spots cut the other way. Canvas-heavy apps get little value without extra work. Bugs that live in browser rendering rather than DOM state can look invisible in playback. And anything happening inside a third-party iframe — including “the payment form is broken,” one of the scariest reports a SaaS can get — will show you the user clicking around a blank rectangle.
Know which kind of bug you’re hunting, and you’ll know whether the replay can show it to you.
See the bug the way your user did
LogReplay captures session replays, console output, network requests, and errors in one timeline — so you stop guessing what happened before the ticket arrived.
Try LogReplay free