CloseTrace

Open source

rrweb

Definition

rrweb (record and replay the web) is an open-source MIT-licensed JavaScript library that records DOM mutations, user inputs, and network metadata as a serialized event stream and replays them inside a sandboxed iframe. Created by Yuyz0112, it powers the session replay features of PostHog, Sentry, OpenReplay, Highlight, and CloseTrace.

Also called: record-and-replay-the-web

What is rrweb in one paragraph?

rrweb is the de-facto open-source recorder for web session replay. It is a small JavaScript library (~50 KB gzipped for the recorder) that takes an initial DOM snapshot, then streams every change to that DOM as a list of typed events. A separate rrweb-player package consumes those events and rebuilds the original page inside an iframe so the recording can be scrubbed like a video — except it is a real DOM, not pixels.

Who created it and what is the license?

  • Author: Yuyz0112 (Yanzhen Yu)
  • First public release: 2018
  • License: MIT
  • Repository: github.com/rrweb-io/rrweb
  • Written in: TypeScript

Because it is MIT-licensed, commercial vendors can embed it without restriction, which is why most of the session replay industry runs on top of it.

How does the recorder work at a high level?

The recorder has three responsibilities:

  • Take a serializable snapshot of the current DOM, including computed styles for inline elements and the contents of stylesheets
  • Subscribe to every source of change (DOM, input, mouse, scroll, viewport, network)
  • Emit each change as a typed event onto a callback the host application provides

Sources of change are wired up via standard browser APIs:

  • MutationObserver for DOM tree changes
  • addEventListener for input, click, scroll, mousemove, touchstart, selectionchange
  • A monkey-patched CSSStyleSheet.prototype.insertRule for stylesheet edits
  • Wrappers around XMLHttpRequest and fetch for network metadata
  • MediaQueryList and ResizeObserver for viewport changes

How do you start recording in code?

The minimal example from the rrweb README:

import * as rrweb from "rrweb";

const events = [];

const stopFn = rrweb.record({
  emit(event) {
    events.push(event);
  },
  maskAllInputs: true,
  maskInputOptions: { password: true },
  blockClass: "rr-block",
  ignoreClass: "rr-ignore",
});

// Later, ship `events` to your backend
// stopFn() to stop recording

The emit callback fires every time a new event is produced. In production you batch events, gzip them, and send them to your backend on a timer or on visibilitychange.

What event types does rrweb produce?

TypeDescription
0DomContentLoaded
1Load
2FullSnapshot — the initial serialized DOM tree
3IncrementalSnapshot — a delta (mutation, input, scroll, mouse, etc.)
4Meta — viewport size, URL
5Custom — user-defined events
6Plugin — events from rrweb plugins

Type 3 is by far the most frequent and contains its own sub-source enum (Mutation, MouseInteraction, Scroll, Input, MouseMove, etc.).

How does the replayer work?

rrweb-player (or rrweb.Replayer directly) takes the array of events and:

  1. Creates a sandboxed iframe with sandbox="allow-same-origin"
  2. Rebuilds the FullSnapshot inside that iframe by setting innerHTML and re-attaching stylesheets
  3. Walks forward through IncrementalSnapshots, applying each one in time order
  4. Renders a virtual cursor and visual click pulses on top
  5. Exposes play, pause, goto(timestamp), and a timeline scrubber

Because it is a real DOM, you can right-click and inspect a replay in DevTools just like a live page.

Which products are built on rrweb?

  • PostHog Session Replay
  • Sentry Session Replay (forked variant)
  • OpenReplay
  • Highlight.io
  • CloseTrace
  • Many internal observability stacks at companies that built their own player

This makes rrweb's event format a de-facto standard — replays can often be moved between tools.

What about privacy?

rrweb ships with built-in privacy primitives:

  • maskAllInputs masks every input value
  • maskInputOptions lets you enable masking per input type
  • blockClass / blockSelector skips entire subtrees
  • ignoreClass skips capturing inputs on matching elements
  • A maskTextFn callback for custom redaction (PII, credit cards, etc.)
  • Password fields are masked unconditionally

How it relates to CloseTrace

CloseTrace uses rrweb for replay capture with browser-side privacy controls. Its lightweight core tracker records form, rage-click, and dead-click signals alongside the replay stream so those events can be shown in session evidence and Lead Recovery.