rrweb 2026-06-22

rrweb Replays Coming Up Blank? The Usual Suspects

An rrweb replay blank screen has about six realistic causes, and in my experience they occur in a fairly stable order: no full snapshot in the event stream, stylesheets the player can’t fetch, CSP blocking the player’s reconstruction, out-of-order timestamps, iframe or shadow DOM content that was never serialized, and CSS leaking between the player and its host page. Work the list top to bottom and you’ll find it; the top two cover most cases.

There’s a particular flavor of frustration to debugging your debugging tool. Deep breath. rrweb is deterministic — a blank player is missing data or blocked rendering, never magic.

Before anything else, run this in the console on the page hosting your player:

const types = events.map(e => e.type);
console.log('full snapshots:', types.filter(t => t === 2).length);
console.log('first types:', types.slice(0, 5));

Type 2 is FullSnapshot. That one number decides which half of this list you’re in.

Suspect 1: no full snapshot (the cause of most rrweb replay blank screens)

rrweb records one full DOM serialization at start, then incremental diffs. The player rebuilds the page from the full snapshot and applies diffs on top. No full snapshot means diffs applied to nothing — a perfectly blank, perfectly “working” player.

How you lose it:

Fix: guarantee every independently-playable chunk begins with a type-2 event, and checkpoint periodically during long recordings.

Suspect 2: CORS-blocked stylesheets

The player rebuilt the DOM fine — but all your CSS lives on a CDN, the replay iframe requested it from the player’s origin, and the CDN said no. What you get is either a truly blank page or the distinctive “1998 layout” of unstyled HTML. Check the network tab of the page hosting the player: rows of CSS requests in red mean you’re here.

Options, in descending order of correctness:

  1. Enable rrweb’s stylesheet inlining at record time (inlineStylesheet: true is the default — check that someone didn’t disable it to save payload bytes; this exact trade-off is covered in the rrweb record options that actually matter).
  2. Add your player’s origin to the CDN’s Access-Control-Allow-Origin (see MDN’s CORS documentation for the header mechanics).
  3. Proxy stylesheet requests through your own backend. Works, but now you’re caching other people’s CSS. Last resort.

Note that cross-origin stylesheets are also invisible to rrweb’s serializer at record time via CSSStyleSheet.cssRules — the browser blocks reads on cross-origin sheets. So this suspect can bite at either end of the pipeline.

Suspect 3: CSP on the player’s host page

Your dashboard’s Content-Security-Policy applies to the replay iframe rendered inside it. If style-src doesn’t allow unsafe-inline, the player can’t inject the recorded styles; if img-src is strict, every image is a hole. The giveaway is a console full of “Refused to apply inline style” violations — the replay isn’t blank so much as forbidden.

The player’s iframe needs a permissive sandbox relative to your app’s CSP. Scope a relaxed policy to the replay route rather than loosening your whole dashboard.

Suspect 4: timestamp disorder

Events must be sorted by timestamp before feeding the player. If your ingest pipeline stores batches in arrival order and a retry delivers batch 3 before batch 2, the player may seek past the full snapshot and render nothing until you scrub backwards. The tell: replay is blank at t=0 but flickers to life when you drag the timeline.

Sort on read. It’s one line, and arrival order is a lie the moment you have retries.

Suspect 5: iframes and shadow DOM

Cross-origin iframes cannot be serialized — the browser won’t let rrweb see inside them, full stop. If your app is itself rendered inside a cross-origin iframe (embedded checkout, admin panel inside a parent product), the recording contains an empty frame and the replay is honestly, correctly blank.

Same-origin iframes and shadow DOM are recordable but historically needed opt-in; on older rrweb versions, web-component-heavy apps produce hollow replays where the page chrome renders and every component is a void. Upgrade, and verify your version serializes shadow roots.

Suspect 6: player CSS isolation

Last and least frequent: the replay data is perfect and your own dashboard’s CSS is destroying it. A global iframe { display: none }, an overzealous CSS reset, a parent container with height: 0 — I’ve seen each of these produce a “blank replay” that was actually a fully rendered replay in an invisible box.

Inspect the player iframe’s computed dimensions. If it’s rendering into 0×0 pixels, the bug report should go to whoever wrote your dashboard styles, which may require apologizing to yourself.

The five-minute triage, condensed

Count type-2 events; zero means a recording/chunking problem and you can stop reading network tabs. Snapshot present: check the player page’s console and network tab — red CSS is suspect 2, CSP violations are suspect 3. Blank-then-flickers-on-scrub is timestamps. Hollow components point at iframes or shadow DOM. And measure the iframe before blaming rrweb, because sometimes the void is your own CSS.

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