RePlaya: Self-Hosted Browser Session Replay with Live Tailing
RePlaya is a self-hosted browser session replay tool that allows developers to capture, replay, and live-tail user sessions. Built on S2, it eliminates the need for a separate database, message bus, or object store by storing each session as a single S2 stream.
Architecture: Stream-Based Session Storage
RePlaya uses S2 streams as the primary primitive for all session data. This design replaces the traditional multi-service backend (which typically requires a relational database for metadata, an object store for blobs, and a message bus for ingestion) with a single Node.js server and S2.
Storage and Timeline
Each session recording is treated as an append-only, ordered, and timestamped sequence of events.
- Storage: rrweb events are appended to the session's S2 stream via the Producer API. Large events are framed across multiple S2 records and reconstructed during playback.
- Timeline: RePlaya uses
timestamping.mode: client-require, ensuring that the rrweb capture time is embedded in each S2 record's timestamp, which serves as the scrub timeline during playback.
Live Tailing and Listing
Because S2 streams can be tailed as they are written, RePlaya provides live playback of active sessions. The GET /api/sessions/:id/live endpoint opens an S2 read session from the snapshot tail and bridges new records to the browser via Server-Sent Events (SSE).
Session listing is handled through lexicographic ordering of stream names. Streams are named using inverted timestamps (sessions/<inverted timestamp>), allowing streams.list({ prefix: "sessions/" }) to return the newest sessions first without needing a separate database to track order.
Implementation and Deployment
RePlaya can be deployed using S2 Cloud or a self-hosted s2-lite instance to maintain full infrastructure control.
Quickstart and Installation
To get started, users need an S2 access token and a basin. The environment configuration is managed via .env.local:
S2_ACCESS_TOKEN=your-token
S2_BASIN=your-basin
PORT=8787
For local development, the project uses pnpm install and pnpm dev. For production-style local runs, pnpm build followed by pnpm start serves both the API and dashboard from Express on a single port.
Drop-in Recorder
Instrumentation is achieved by adding a JavaScript snippet to the target web page. The recorder supports metadata for grouping captures via the source parameter, as well as distinctId and userId for identity tagging.
replaya("init", {
apiHost: "https://replaya.example.com",
source: "web-app"
});
Privacy and Masking
By default, the recorder uses rrweb's maskAllInputs to mask all input, select, and textarea values, ensuring sensitive keystrokes (like passwords) are never sent to the server. Developers can disable this for internal tools by passing maskAllInputs: false or adding data-mask-all-inputs="false" to the script tag. Additionally, the replaya-block class can be used to omit specific regions from recordings, and replaya-ignore can skip subtree changes.
Production Configuration and Security
RePlaya is designed with a clear boundary between the public collector and the private dashboard.
Access Control
The read APIs and dashboard have no built-in authentication; the deployment boundary is the access control. In production, the dashboard and GET /api/sessions* endpoints should be placed behind a VPN, Tailscale, or SSO layer (e.g., Cloudflare Access).
Ingest Security
To secure the public collector, the following settings are part of the production configuration:
REPLAYA_PROJECT_KEY: A public write key used to authenticate ingest.REPLAYA_APPEND_TOKEN_SECRET: A stable random value used to generate short-lived append tokens.REPLAYA_ALLOWED_CAPTURE_ORIGINS: A list of allowed origins to prevent unauthorized captures.NODE_ENV=production: Enforces ingest authentication and disables the recorder test fixture.
Comparison with Traditional Backends
| Feature | Typical Replay Backend | RePlaya |
|---|---|---|
| Services to run | Message bus, analytics store, relational DB, object store, search index | One Node server + S2 |
| Live sessions | Playback after ingest/flush delay | Live tail of active sessions via the same stream |
| Stored recording | Blobs in object storage; metadata in databases | One ordered S2 stream per session |
| Self-host footprint | Multi-service cluster (often Kubernetes) | Single process + S2 (or s2-lite) |
Community Discussion
While the technical implementation of RePlaya is praised for its efficiency, some community members have raised ethical concerns regarding session replay tools.
"I wonder what people think about session replay, ethically. Is it okay to do? Do you think visitors should be informed about it?"
Others highlighted the utility of these tools for qualitative analysis, noting that session replays are crucial for understanding new features before quantitative metrics become statistically significant.