Skip to main content

Extension content script timeouts and snapshot errors

Dashboard: DOM recorder in Axiom
Service: Chrome Extension

Overview​

The extension captures DOM snapshots of a page for session replay and automation evidence. Snapshot serialization (rrweb takeFullSnapshot()) is synchronous and runs on the page's main thread, so a heavy page blocks everything while it serializes. Almost every snapshot timeout or capturePage failure traces back to this cost.

A snapshot request travels through four layers, each with its own timeout and failure mode, so "the snapshot failed" can mean very different things:

  1. Slow page serialization — the page is too expensive to snapshot in time (most common root cause).
  2. Recorder problem — the injected recorder is alive but can't produce a result (overlapping requests, stale lock, or a dead realm after navigation).
  3. Content-script timeout — the request reached the content script but got no timely answer (usually a symptom of slow serialization or a recorder problem).
  4. Background gave up — the background service stopped retrying after its own timeout.

Start on the dashboard​

Open the Snapshot performance (recorder) dashboard. If you have the affected session, set the Session ID filter and adjust the time range, otherwise set the time range around the failure:

  • Serialization latency p50 / p95 / p99 (ms) and Heavy serializations (> 2s / > 10s) — show whether serialization is taking too long. A rising p95/p99 or a spike of > 10s snapshots points to slow page serialization.
  • Snapshot outcomes (serialized / cacheHit / skipped) and Cache vs Skip — show whether the circuit breaker (skipped) and cache are engaging as expected. A surge of skipped means pages are repeatedly too heavy to serialize.
  • Page stats on slow snapshots > 1s — averages of longTaskTotalMs, nodeCount, topFrameCanvasCount, topFrameImageCount for slow snapshots. High canvas/image counts are usually the real driver (heavy content inlined synchronously). high longTaskTotalMs means the page itself was contending for the main thread. Node count alone is a weak predictor.
  • capturePage failures & content-script timeouts — confirms what actually failed and classifies it: timeout (no retry), failed (retries exhausted), or skipped (max duration). Start here to know which failure mode you are dealing with.

Dig into the raw logs​

When the dashboard isn't enough and you need to dig deeper, query the logs dataset (service legion-extension). Scope every query with the session id from the dashboard.

  • Full timeline for one session — order everything the extension logged to see the last successful step before the failure:
['logs']
| where ['service.name'] == "legion-extension"
| where tostring(['attributes.sessionId']) == "RELEVANT_SESSION_ID"
| project _time, body, ['attributes.host'], ['attributes.durationMs'], ['attributes.isTimeout']
| sort by _time asc
  • Content-script timeout vs dead recorder — Persistent snapshot timed out / Timed out after 12000ms are timeouts, not crashes, the work may still be running on a frozen thread. After a timeout the content script pings the recorder and logs recorder ping after timeout:
    • alive → slow page serialization. The recorder is fine, the page was just too slow. Expect a recorder snapshot metrics line with a large durationMs to arrive after the timeout.
    • no response → recorder problem. The recorder realm is dead (page wiped) and needs re-injection.
['logs']
| where ['service.name'] == "legion-extension"
| where tostring(['attributes.sessionId']) == "RELEVANT_SESSION_ID"
| where body contains "ping after timeout" or body contains "snapshot timed out" or body contains "Timed out after"
| project _time, body, ['attributes.host']
| sort by _time asc
  • Recorder-level errors — Snapshot already in progress (overlapping requests during a freeze) or a non-empty staleLockReclaimedAfterMs (a prior snapshot didn't release its lock cleanly) both indicate a recorder problem, not slow page serialization.
  • No telemetry at all — if there is no recorder snapshot metrics line for the host/session, the recorder likely was not injected or the page was non-capturable.

Actions​

  • Open a Linear issue and attach the affected host, the relevant data from telemetry, and which root cause was identified (slow page serialization, recorder problem, etc.).
  • If the issue started after a recent release, treat it as a likely regression and prioritize rollback/fix decisions.