TL;DR, Quick Answer
8 min readThe open-source library rrweb records a browser session as one serialized DOM snapshot followed by a stream of incremental events (DOM mutations, mouse movement, clicks, scrolls, resizes and input), then rebuilds the page inside a sandboxed iframe to replay it. It records no video. It is MIT licensed, and its guide now points new projects to @rrweb/record and @rrweb/replay instead of the older rrweb package. Out of the box it masks only password inputs; maskAllInputs, blockClass, maskTextClass and their selector twins widen that.
What is rrweb?
The open-source library rrweb, short for "record and replay the web", records a user's session in the browser as structured JSON and plays it back as a watchable reconstruction of the page. The project README describes it as "a tool for recording and replaying users' interactions on the web." It lives at github.com/rrweb-io/rrweb, the repository was created in October 2018, and the code is written in TypeScript so the recorder and the player share one typed event format.
rrweb is a library, not a product. It gives you a recorder that emits events and a player that consumes them. Where those events go, how long you keep them and who can watch them is your code's job. That split is why so many commercial replay tools start from it, and why session replay in general looks so similar from vendor to vendor.
Does rrweb record video?
No. rrweb records the state of the page, not its pixels. On start, the recorder walks the DOM and serializes it into a tree of nodes, each with a unique numeric id. The project's serialization doc calls this output "descriptive": scripts are swapped for placeholder noscript tags, input values are copied into a value attribute, relative URLs become absolute, and external stylesheets are inlined so the replay still renders when the original CSS is unreachable.
After that full snapshot, everything is a diff. The recorder attaches a MutationObserver and a set of listeners, and the observer doc lists what it captures:
- DOM changes: node creation, deletion, attribute changes and text changes
- Mouse movement
- Mouse interaction: mouse up and down, click, double click, context menu, focus, blur, and touch start, move and end
- Page or element scrolling
- Window size changes
- Input
Every event carries a timestamp and a numeric type. The event types are DomContentLoaded, Load, FullSnapshot, IncrementalSnapshot, Meta and Custom, and incremental events add a data.source field that says whether the change was a mutation, a mouse move, a scroll and so on.
The replayer rebuilds the snapshot inside an iframe and applies the incremental events in order. It never executes the recorded page's JavaScript. rrweb's sandbox doc explains that the iframe's sandbox attribute blocks form submission, pop-ups such as window.open, and scripts, including inline handlers and javascript: URLs. Because the page is rebuilt from nodes, text in a replay is real text you can select. If you do need a video file, the monorepo ships rrvideo, which it describes as "a tool for transforming the session recorded by rrweb into a video."
The same dependency on MutationObserver sets rrweb's browser floor. The guide states that "rrweb does not support IE11 and below because it uses the MutationObserver API".
Which rrweb packages should you install?
The rrweb guide recommends @rrweb/record plus @rrweb/replay for most projects, and @rrweb/all when you want one import for recording, replay and the packer. The table lists the main packages in the monorepo as its packages README describes them. Every one was at version 2.1.6 on npm, published 18 September 2026, when this page was written.
| Package | What it does |
|---|---|
@rrweb/record | The recording code, meant to run in your front-end app or page |
@rrweb/replay | Rebuilds and replays recorded events in an iframe |
@rrweb/all | Record, replay and the packer in one package, no plugins |
rrweb-player | A playback UI with pause, fast-forward and seeking, built on @rrweb/replay |
rrweb-snapshot | Serializes the DOM and rebuilds it, the basis of the FullSnapshot event |
@rrweb/packer | Per-event compression before network transfer |
@rrweb/types, @rrweb/utils | Shared types and helpers |
rrdom, rrdom-nodejs | A virtual DOM used to fast-forward mutations during replay, plus a Node.js version |
rrvideo | Converts a recording into a video |
rrweb | The original package with record and replay together |
The original rrweb package is where the documentation and the registry disagree. The guide says: "The rrweb package is deprecated. It still works, but new projects should use @rrweb/record and @rrweb/replay." On npm, rrweb 2.1.6 carries no deprecation notice, and it still out-downloads its replacement: npm's download API counted 1,874,214 downloads of rrweb in the week of 15 to 21 September 2026, against 498,366 for @rrweb/record. Anyone installing it gets no warning. If you are starting fresh, follow the guide and install the split packages, because the rrweb package is the one the maintainers plan to slim down and remove.
What licence is rrweb released under?
rrweb is released under the MIT License. The repository's LICENSE file opens with "Copyright (c) 2018 Contributors", and npm lists MIT for each package above. MIT lets you use, modify and ship rrweb in closed-source commercial software as long as you keep the copyright and licence notice.
That permissive licence explains the forks. Sentry's replay package depends on @sentry/rrweb and @sentry/rrweb-snapshot, according to its package.json in the sentry-javascript repository. PostHog's browser SDK depends on @posthog/rrweb and @posthog/rrweb-record. Both vendors maintain their own copy, so a fix in upstream rrweb does not reach their users until the vendor merges it, and the option names and defaults in their SDKs differ from rrweb's own.
Which rrweb options control privacy?
rrweb exposes its privacy controls as options on record(). The names and defaults below are copied from the Record Options table in guide.md.
| Option | Default | What it does |
|---|---|---|
blockClass | 'rr-block' | Elements to block, as a string or RegExp |
blockSelector | null | A selector for elements to block |
ignoreClass | 'rr-ignore' | Elements whose input events are ignored, as a string or RegExp |
ignoreSelector | null | A selector for elements to ignore |
maskTextClass | 'rr-mask' | Elements whose text is masked, as a string or RegExp |
maskTextSelector | null | A selector for elements to mask |
maskAllInputs | false | Masks all input content as * |
maskInputOptions | { password: true } | Masks some kinds of input |
maskInputFn | none | Custom logic for masking input content |
maskTextFn | none | Custom logic for masking text content |
ignoreCSSAttributes | null | An array of CSS attributes to ignore |
recordCanvas | false | Whether to record canvas elements |
recordCrossOriginIframes | false | Whether to record cross-origin iframes, which needs rrweb injected into each child frame |
The three classes behave differently, and people mix them up. The guide's privacy section spells it out. An element with .rr-block "will not be recorded. Instead, it will replay as a placeholder with the same dimension." An element with .rr-ignore "will not record its input events." And "all text of elements with the class name .rr-mask and their children will be masked." Blocking removes the element. Ignoring keeps the element but drops what the user types into it. Masking keeps the layout and replaces the characters.

What does rrweb mask by default?
rrweb masks one thing by default: the value of password inputs. The guide says it in one line, "input[type="password"] will be masked by default", and the recorder source confirms it: when maskAllInputs is not true and you pass no maskInputOptions, the recorder falls back to { password: true }.
Flowsery
Start Your 14-Day Free Trial
Real-time dashboard
Goal tracking
Cookie-free tracking
Everything else, including email, phone, address and free-text fields, leaves the browser as typed unless you configure more. maskInputOptions accepts these keys, from MaskInputOptions in the rrweb-snapshot types: color, date, datetime-local, email, month, number, range, search, tel, text, time, url, week, textarea, select and password. Setting maskAllInputs: true switches all of them on at once.
No option exists to unmask a child inside a masked parent. rrweb has no unmask or unblock setting, so vendors that offer one built it into their fork. If you compare libraries on defaults, our breakdown of where PII redaction defaults leave data exposed puts rrweb next to Sentry and Clarity.
A practical rule for a new install: start with maskAllInputs: true, add maskTextClass or maskTextSelector to any container that renders account data, and put blockClass on third-party widgets you have no reason to see.

How do you reduce the size of an rrweb recording?
rrweb's storage recipe lists three strategies: block DOM elements that emit many events, use the sampling config to drop events, and compress or deduplicate what you keep.
The sampling option thins events inside a recording rather than choosing which sessions to record. Its keys come from the SamplingStrategy type. mousemove takes false or a throttle threshold, mouseInteraction takes false or a per-interaction map, scroll and media take throttle thresholds, input takes 'all' or 'last', and canvas takes 'all' or a snapshot rate between 1 and 60 per second. The recipe's example sets scroll: 150 with the comment "do not emit twice in 150ms" and input: 'last' to keep only the final value of a typed sequence. That is event-level sampling, which is a different lever from the session replay sampling rate that vendors expose.
For compression, @rrweb/packer provides a pack function you pass as packFn, and the matching unpack goes to the replayer as unpackFn. The recipe notes that compressing the whole session on the backend usually beats per-event compression. slimDOMOptions strips parts of the DOM such as scripts and comments, and checkoutEveryNth or checkoutEveryNms take a fresh full snapshot at intervals, which lets you keep only the last stretch of a session when an error fires. The guide warns that this is approximate: with checkoutEveryNth: 200 you end up sending "the last 200 to 400 events".
Recording cost is also a page speed question. The published numbers on what a recorder adds to bundle size and main-thread time are collected in how much session replay slows a site down.
Frequently asked questions
Is rrweb free to use commercially?
Yes. rrweb is MIT licensed, so you can use and modify it in closed-source commercial software. You must keep the copyright notice and the licence text with the code you ship.
Does rrweb capture what users type?
Yes, unless you mask it. rrweb records input events and masks only input[type="password"] by default. Set maskAllInputs: true or list specific input types in maskInputOptions to mask more.
What is the difference between blockClass and maskTextClass in rrweb?
blockClass (default 'rr-block') removes an element from the recording and replays a same-sized placeholder. maskTextClass (default 'rr-mask') keeps the element and replaces the text inside it and its children.
Should I install rrweb or @rrweb/record?
Install @rrweb/record for recording and @rrweb/replay for playback. The rrweb guide calls the combined rrweb package deprecated, even though npm shows no deprecation warning on it.
Can rrweb record canvas and iframes?
Yes, both are off by default. recordCanvas: false and recordCrossOriginIframes: false are the defaults, and cross-origin iframes also need rrweb injected into each child frame.
Which browsers does rrweb support?
rrweb supports browsers that implement MutationObserver. Its guide states that it does not support Internet Explorer 11 and below.
How does rrweb's sampling option reduce recording size?
The sampling config thins events inside a session instead of dropping whole recordings. scroll and media take a throttle threshold, mousemove takes one too, and input accepts 'last' to keep only the final value of a typed sequence. The storage recipe's example sets scroll: 150 so a scroll only fires once every 150 milliseconds.
Flowsery
Start Your 14-Day Free Trial
Real-time dashboard
Goal tracking
Cookie-free tracking
Can you convert an rrweb recording into a video file?
The rrweb monorepo ships rrvideo, described as "a tool for transforming the session recorded by rrweb into a video." This turns a recording made of a DOM snapshot and mutations into an actual video file. rrweb itself still records no video; rrvideo is a separate conversion step run afterward.
How many downloads does the deprecated rrweb package get compared to @rrweb/record?
In the week of 15 to 21 September 2026, npm counted 1,874,214 downloads of the rrweb package against 498,366 for @rrweb/record. The guide calls rrweb deprecated, but npm shows no deprecation notice on it, so installing it shows no warning. The older package still gets downloaded far more than its replacement.
Do Sentry and PostHog use the original rrweb package directly?
Sentry and PostHog each maintain their own fork rather than depending on rrweb directly. Sentry's replay package depends on @sentry/rrweb and @sentry/rrweb-snapshot, and PostHog's browser SDK depends on @posthog/rrweb and @posthog/rrweb-record. A fix in upstream rrweb only reaches their users once the vendor merges it, and each fork's option names and defaults differ from rrweb's own.
Was This Article Helpful?
Let us know what you think!
See us more often in Google
One click marks Flowsery as a preferred source, so our articles sit higher in your Top Stories, AI Mode, and AI Overviews.
Before you go...
Flowsery
Revenue-first analytics for your website
Track every visitor, source, and conversion in real time. Simple, powerful, and cookie-free.
Real-time dashboard
Goal tracking
Cookie-free tracking
Related Glossary Terms


How Session Replay Works, and What It Cannot See
A session replay rebuilds a visit from DOM mutations and input events, not video. See what it captures, what masking hides, and how it differs from heatmaps.


Where PII Redaction Session Replay Defaults Leave Data Exposed
PII redaction session replay defaults vary wildly: rrweb masks only passwords, Sentry masks all text, Clarity masks numbers and emails.


What Seven Vendors Publish on Session Replay Data Retention
Session replay data retention compared from vendor docs: FullStory, Hotjar, Clarity, LogRocket, PostHog, Sentry and Datadog, plus what GDPR requires.


How Much Does Session Replay Slow Down Website Speed?
The real answer to does session replay slow down website speed, with published rrweb and Sentry numbers for script size, main-thread CPU, and upload bandwidth.


How a Google Analytics Opt Out Works, and What Each Method Blocks
A Google Analytics opt out can be a browser add-on, a ga-disable window flag or denied consent. What each one blocks, who controls it, and where it stops.


Where the Data Comes From in Session Replay vs Heatmaps
Session replay vs heatmaps: one visit against many, and how Hotjar, Datadog, PostHog, Clarity and FullStory build heatmaps from, or apart from, recordings.
Related Articles


How a Session Replay Sampling Rate Works in Sentry, PostHog and Others
A session replay sampling rate sets what share of visits get recorded. See how Sentry, PostHog, LogRocket, Datadog and Clarity document it.


What Session Replay GDPR Compliance Actually Requires of You
A session replay GDPR review turns on four things: an Article 6 lawful basis, Article 9 special category data, ePrivacy Article 5(3) consent, and a DPIA.


Where Rage Clicks vs Dead Clicks Actually Differ
The rage clicks vs dead clicks split is about cause, not severity. Detection thresholds published by PostHog, Hotjar, FullStory, LogRocket and Clarity.

