Download size
| Size | |
|---|---|
| Minified | 105.5 KB |
| gzip | 36.3 KB |
| brotli | 31.9 KB |
| Budget (gzip) | 45 KB |
This is ar.min.js, the file the script-tag snippet loads, with the recording engine (rrweb) inside it. The build fails if the gzipped file grows past the budget, so a dependency upgrade cannot quietly make every customer’s site heavier. The player that replays sessions is not in it; only the dashboard loads that.
How it loads
- The snippet defines a small queue and adds the script with
async, so the browser keeps parsing and rendering the page while it downloads. Calls made before it arrives —init,identify,track— wait in the queue and run in order. - With
requireConsent, the recorder records, stores and sends nothing until consent is given. WithsampleRate, a visitor who is not sampled is not recorded at all. - Nothing the recorder does may throw into your page: its errors are caught and, with
debug: true, written to the console.
What it does on the main thread
- Once per page: a snapshot. When recording starts it reads the page once and serialises it, with readable stylesheets as text. This is the largest single piece of work, and it grows with the size of the page.
- While the visitor is there: changes. A
MutationObserverand event listeners note what changed — elements, text, scrolling, clicks, form input (masked on the device) — instead of reading the page again. - Every 5 seconds: a send. Changes are batched and sent with
fetch; when the tab is hidden or closed, what is left goes withkeepaliveorsendBeacon. Batches are JSON and are not compressed by the recorder. - Not done at all: canvas recording, font collection, screenshots or video.
Measured in Chrome
We loaded a shop page — product cards, a form, a stylesheet — in Chrome 156.0.8078.47, once without the recorder and once with the exact snippet customers paste, 5 times each, and took the median of the difference in main-thread time Chrome itself reports. Then we did the same with the CPU slowed four times, Chrome’s stand-in for a mid-range phone. Ingest was a local stub, so the network is not part of these numbers.
| Typical page, 921 elements | Heavy page, 2,721 elements | |
|---|---|---|
| Added main-thread time while loading | 19 ms | 23 ms |
| … with the CPU slowed 4× | 75 ms | 107 ms |
| Longest single task, 4× slower CPU | none over 50 ms | 65 ms |
| Added main-thread time per second of activity | 7.7 ms | 4.4 ms |
| … with the CPU slowed 4× | 13.1 ms | 12.9 ms |
| Long tasks during activity, 4× slower CPU | 0 | 0 |
| Largest upload (the snapshot, uncompressed) | 165 KB | 491 KB |
“Activity” is 10 seconds in which the page changes twenty elements and scrolls ten times a second — busier than most visits. Chrome counts a task of 50 ms or more as long, because the page cannot answer a tap while it runs. Measured on Apple M4.
Limits worth knowing
A page whose snapshot is larger than 512 KB is not recorded: the recorder stops for that page and says snapshot_too_large in the console with debug: true. On our test page that happens a little past 3,000 elements. See sessions cut short.
- The snapshot’s cost grows with the page. On the heavy page with a slow CPU it can be a long task; that is the moment to consider
sampleRateorar-blockfor a large widget nobody needs to see. - These are lab numbers from one machine. Your page, your visitors’ devices and other scripts on the page will move them, in either direction.