Replayborg documentation
Self-hosted session replay for WordPress. Watch how visitors actually use your site — the pages they moved through, where they clicked, how long they stayed — with every recording captured by your own site and stored in your own database.
What Replayborg is
Analytics tells you that a page was visited. A session replay tells you what happened on it: where the visitor's attention went, which link they hovered over twice and did not click, the form field they filled in and then cleared, the point at which they left. It is the difference between a number and a story.
Replayborg records those visits with rrweb, which captures the page as a stream of DOM changes rather than as video — a recording is a few dozen kilobytes, not a few dozen megabytes — compresses each batch, and writes it into your WordPress database.
Nothing leaves your site. There is no external service, no API key, no account, and no request to any host but your own. If you can reach the recordings, it is because they are sitting in your database. This is the whole reason the plugin exists: the well-known session replay products are all SaaS, which means handing your visitors' browsing to a third party.
What ships in 1.0
Heatmaps, funnels, error tracking, frustration detection and visitor profiles are not in this release. They are the obvious next modules, and the plugin is built so they can arrive without disturbing what you already have — see Hooks for the module rule that makes that safe.
Install
Requirements: WordPress 6.4+ and PHP 8.2+, on whatever database WordPress itself runs on.
- Search for SB Replayborg in Plugins → Add New, or install it from the WordPress.org plugin directory.
- Activate it through the Plugins menu.
- Open Replayborg in the admin menu.
The directory lists it as SB Replayborg — SB for Stackborg, who publish it. Everywhere you actually use it, in the admin menu and on its screens, it is Replayborg.
That is the whole setup. There is nothing to configure before it works: activating it prepares its storage, schedules the daily cleanup, and starts recording. The defaults are chosen so that the first thing you do — opening your own site to check — produces a recording you can watch.
Your first recording
- Open your site's front end in a normal browser window and click around a few pages.
- Wait a moment. Frames are flushed every five seconds and again when the page is closed.
- Go to Replayborg in wp-admin. The visit is in the list.
No recording appeared? The most common causes are a caching plugin serving a page without the recorder, an ad blocker, or a page that was open for less than a second. See Troubleshooting.
The session list
One row per visit. Each cell carries two lines — the value, and the fact that qualifies it — so you can tell a bounced mobile visit from a long desktop one without opening anything.
| Column | What it tells you |
|---|---|
| Visitor | Name and avatar for signed-in users; the anonymous visitor id otherwise |
| Journey | The page the visit started on, and the page it ended on |
| Source | Where the visit came from — a campaign parameter, a referring site, or direct |
| Device | Desktop, mobile or tablet, with the screen size that was recorded |
| Duration | How long the visit lasted |
| Pages | How many pages the visitor moved through |
| Recorded | When it happened, in your site's timezone and date format |
Columns drop out as the screen narrows, in order of how much each one adds beyond the rest of the row. Above the table, four figures summarise the page you are looking at — and they say on this page rather than pretending to be site-wide averages, because the list is paginated and a number that quietly means something narrower than its label is worse than no number.
Everything is in the URL
The page you are on, the sort, and every filter live in the address bar. Open a recording and press Back and you return to the same page of the same filtered list. Bookmark a view, or send it to a colleague as a link, and they see what you saw.
Filtering and sorting
| Filter | Options |
|---|---|
| Search | Any part of the entry or exit URL — type and pause, no button to press |
| Device | Desktop, mobile, tablet |
| Visitor | Signed in, or anonymous |
| Date range | Today, yesterday, last 7 / 30 days, this month, or a custom range |
| Sort | Duration, pages, or when it was recorded — either direction |
| Per page | 20, 50 or 100 rows |
Date filters are calendar dates in your site's timezone. That matters more than it sounds: recordings are stored in UTC, so on a UTC+6 site an unconverted "today" would lose everything recorded before 6am and gain the previous evening. Replayborg converts the range before it queries.
Active filters appear as chips under the controls. Each can be removed on its own, or all at once.
Watching a session
Click any row. The player rebuilds the page as the visitor saw it and replays what they did.
| Control | What it does |
|---|---|
| Play / pause | The frame itself is also the play button — click the video |
| ± 10 seconds | Skip back or forward |
| Speed | 1×, 2×, 4×, 8× on one cycling control |
| Skip idle | Jump over the stretches where nothing happened |
| Scrubber | Marked with the point each page of the visit began — click a marker to jump there |
| View | Default, theater (full page width), or full page — Escape leaves full page |
The recording's own aspect ratio is read from its first frame, so a phone capture is shown as a phone rather than letterboxed into a 16:9 box.
Pages visited
Below the player, every page of the visit in order:
- When it began, as an offset into the recording
- Time on page
- Clicks, and clicks per minute — the rate is what separates a page someone read from a page someone hammered
- Share of the session
- Role — entry, exit, or a page the visitor returned to
Clicking any row seeks the player to that page. So does clicking a bar in the activity strip on the right, which shows where in the recording the clicking actually happened.
Who the visitor was
If a visitor is signed in to WordPress, the session is attributed to their user account — avatar, display name, and a link to their profile. If they sign in during the visit, the session is claimed for them at that moment and never re-assigned afterwards.
Anonymous visitors get a random visitor id, generated in the browser and stored there. It is not linked to an identity, it is not shared between sites, and it is the only thing that ties two visits from the same browser together.
Settings and defaults
This release ships no settings screen. The values below are stored in the
sb_replayborg_settings option and can be changed with WP-CLI, a
small snippet, or any options editor.
| Key | Default | What it does |
|---|---|---|
recording_enabled | true | Switch recording off without deactivating the plugin |
mask_inputs | true | Replace typed text before it leaves the browser |
block_selector | empty | CSS selector for elements that are never recorded |
sample_rate | 100 | Percentage of visits to record |
max_session_minutes | 30 | Recording stops after this long |
consent_required | false | Wait for a consent signal before recording |
exclude_roles | empty | Comma-separated role slugs that are never recorded |
retention_days | 30 | How long recordings are kept |
wp option patch update sb_replayborg_settings retention_days 14
wp option patch update sb_replayborg_settings exclude_roles administrator,editor
Nothing is excluded by default, including administrators. The obvious default would be to skip them — their own browsing skews the figures — but a rule you can neither see nor switch off is indistinguishable from the plugin being broken, and the first thing anyone does is open their own site to check that recording works. Exclude yourself once you have seen it work.
Privacy
Session recordings are personal data in most jurisdictions, including under the GDPR. Running this plugin makes you the controller of that data. Replayborg is built to make that manageable, but it cannot make the decision for you.
What the plugin does about it
- Input masking is on by default. Text typed into fields is replaced in the browser, before anything is sent. Passwords, card numbers and message bodies never reach your database.
- Elements can be excluded entirely with a CSS selector — an account panel, a medical form, anything that should not exist in a recording.
- A consent gate can hold recording until your consent tool says the visitor agreed: set
window.sbReplayborgConsent = true. - Nothing is sent anywhere. No third-party service receives any part of a recording, because the plugin does not contact one.
- Suggested policy wording is registered with Tools → Privacy, ready to be added to your policy page.
- Recordings expire — 30 days by default — and are deleted, not archived.
What is still yours to do
- Tell visitors you record sessions, in your privacy policy.
- Decide whether you need consent before recording, and switch the gate on if you do.
- Set a retention period you can justify — shorter is easier to defend.
- Block anything sensitive that masking does not cover, such as a name rendered as page text rather than typed into a field.
- Be able to answer a deletion request. A recording is identified by its session id, and by the visitor id kept in that visitor's browser; a signed-in visitor's recordings also carry their WordPress user id.
The full privacy policy — what the plugin records, what Stackborg receives (nothing), what you are responsible for as the site owner, and wording you can adapt for your own policy — is at Privacy policy.
This documentation page itself requests nothing from any other server — no fonts, no images, no trackers — sets no cookies and collects nothing about you. The one script on it is a dozen inline lines that highlight the section you are reading.
Retention and storage
Recordings live in tables of the plugin's own inside your WordPress database, and the frames are compressed before they are written — rrweb output is repetitive JSON, and roughly 90% of it disappears.
- Retention defaults to 30 days. A daily job deletes recordings past the window, and finalises sessions that have gone half an hour without activity.
- Reading them requires an administrator — the same capability that manages options.
- Deactivating the plugin removes nothing. Deleting it removes the plugin's tables and its settings.
As a rough guide, a five-page visit is a few hundred kilobytes; a small site keeping 30 days is usually tens of megabytes rather than gigabytes. Shorten the window if that matters on your host.
Performance
- The recorder is one script on the front end. It is not loaded in wp-admin, and not loaded at all if recording is off, the sample rate excludes the visit, or a filter says no.
- Frames are batched and flushed every five seconds, and once more when the page is hidden or closed — not on every mouse movement.
- The closing flush uses
sendBeacon, the only transport a browser guarantees during navigation, so leaving a page does not slow it down. - Batches are size-capped, and the endpoint that receives them is rate limited per client, so no single browser can flood the database.
- Reading recordings happens in wp-admin only, and never touches a front-end page load.
Full-page caching is fine. Recording is designed to keep working when a page is served from cache, which is where plugins that depend on per-request tokens usually break.
Hooks
sb_replayborg_should_record — filter
The last word on whether a page view is recorded. It runs before the recorder is enqueued, so returning false means the script is never sent — not that it is sent and does nothing.
// Do not record administrators.
add_filter( 'sb_replayborg_should_record', function ( bool $record ): bool {
return current_user_can( 'manage_options' ) ? false : $record;
} );
// Never record checkout, whatever else is true.
add_filter( 'sb_replayborg_should_record', function ( bool $record ): bool {
return is_page( 'checkout' ) ? false : $record;
} );
sb_replayborg_cleanup — action
The daily retention job. Fire it by hand to test retention without waiting:
do_action( 'sb_replayborg_cleanup' );
Options
Settings live in one option, sb_replayborg_settings, whose keys
are the ones in Settings and defaults. The plugin
keeps three more of its own for the installed version and which modules are
switched on. All of them are removed when the plugin is deleted.
The module rule
Every feature is a module that declares the tables it owns, the REST controllers it contributes and what the recorder should collect for it. The registry boots only the ones switched on — and disabling a module never drops its tables. That constraint is what makes it safe to add features later to sites that already have recordings: existing installs get the feature, and turning it back off does not destroy what it collected.
FAQ
Does any data leave my site?
No. There is no external service, no API key and no account. Recordings are written to your database and read back from it.
Does it work with caching plugins?
Yes, and it is built for them. Nothing the recorder needs is embedded per request, so a page served from cache records exactly like an uncached one.
Will it slow my site down?
One script on the front end, frames batched and flushed every five seconds, and a beacon on unload. See Performance.
Can I stop recording myself?
Yes — set exclude_roles, or use the sb_replayborg_should_record filter. Nothing is excluded by default so that your first check actually produces a recording.
Are passwords recorded?
No. Input masking is on by default and replaces typed text in the browser, before anything is sent.
How much database space does it use?
Frames are GZIP compressed; a typical five-page visit is a few hundred kilobytes. Retention defaults to 30 days and is configurable.
Does uninstalling delete my recordings?
Deactivating does not. Deleting the plugin does — its tables and its settings are removed, and nothing is left behind.
Can I record only some visitors?
Yes — sample_rate records a percentage of visits, and the filter above can decide per page view.
Does it work on multisite?
Each site in a network keeps its own recordings and its own settings, and each is read from that site's own admin. There is no network-wide screen in this release, so a network administrator sees one site at a time.
Troubleshooting
No recordings appear
- Open your site in a browser and view source. If
recorder.jsis not there, something is preventing the enqueue: a filter, an excluded role, a sample rate below 100, or the consent gate waiting for a signal that never arrives. - Check the browser console for blocked requests — ad blockers and strict privacy extensions sometimes stop the beacon.
- Visit more than one page and stay for a few seconds. Very short visits may end before the first flush.
- If a caching or optimisation plugin combines and defers scripts, try excluding
recorder.jsfrom it.
Recordings are there, but signed-in visitors show as anonymous
Attributing a visit to a WordPress user depends on the page being served fresh to that user. If a caching layer is serving logged-in visitors a cached page, WordPress cannot recognise them and the visit is filed as anonymous — exclude logged-in users from full-page caching, which most caching plugins do by default.
The player shows a blank frame
A recording needs its first full snapshot to replay. If the visit began before the recorder finished starting — a very fast bounce, usually — there is nothing to rebuild, and the screen says so rather than showing an empty box.
Old recordings are not being deleted
Retention runs on WP-Cron, which only fires when the site gets traffic. On a quiet site, use a real cron: wp cron event run sb_replayborg_cleanup.
Timestamps look wrong
Every timestamp on these screens uses Settings → General — timezone, date format and time format. Recordings are stored in UTC and converted for display. If the site's timezone is unset, WordPress reports UTC and that is what you will see.
Support
Write to us. One address, answered by the people who build it:
Security issues go to security@stackborg.com instead — please report those privately rather than in public, and give us time to ship a fix before describing the problem anywhere else.
What to include
These five things turn a report into a fix, and their absence turns it into three rounds of questions:
- WordPress version and PHP version
- The Replayborg version
- Any caching, security or optimisation plugin that is active
- What you did, and what you expected instead of what happened
- Anything in the browser console or
wp-content/debug.logat the time
Please do not send database dumps or exported recordings — they contain your visitors' personal data, we do not need them to help, and we would rather not hold them.
Everything on this site
| Page | What is on it |
|---|---|
| Documentation | This page — install, first recording, the session list, filtering, the player, pages visited, settings, privacy controls, retention, performance, hooks, the REST API, building the JavaScript, FAQ and troubleshooting |
| Privacy policy | What is recorded, where it is stored, what we never receive, what you are responsible for as the site owner, and wording you can adapt for your own policy |
| The plugin | Replayborg on the WordPress.org directory — download, ratings, version history and the changelog |