packstub/session-replay
| Install | |
|---|---|
composer require packstub/session-replay |
|
| Latest Version: | v1.0.0-beta.2 |
| PHP: | ^8.3 |
| License: | MIT |
| Last Updated: | Oct 2, 2026 |
| Links: | GitHub · Packagist |
Session Replay for Laravel
Record what a person did in the browser, keep the recording on your own disk and database, and watch it inside your own app, behind a gate you define. Built on rrweb. Free and open source (MIT).
"The form did nothing when I clicked save" becomes a 40-second replay with the console error and the failed Livewire request marked on the timeline.
Beta. 1.0 is close and feedback is very welcome in the issues. Until 1.0, names and config may still change between betas; the changelog says how to upgrade.
- Docs: docs/
- Support: GitHub issues
Features
- One Blade directive:
@sessionReplaybefore</body>records the page, with nothing to build or publish. - Private by default: every input masked, no IP address stored, an anonymous mode, sensitive pages left out.
- Recordings stay with you: gzip chunks on any Laravel disk, the index in four tables on your connection.
- Markers on the timeline: errors, failed Livewire requests, web vitals, rage clicks, page views and your own moments.
- Small recordings: stylesheets stored once, unused attributes dropped, batches gzipped in the browser.
- A gate decides who watches:
viewSessionReplayguards the list, the player and every file behind them. - A link in every log line: the recording's id and URL in Laravel's
Context, so error reports point at the replay. - Multi-tenant aware: a recording stays in one workspace, and the tables can live on your central connection.
- Friendly to cached pages: the recorder's token can outlive a full-page cache.
- Five languages: the viewer and the player in English, German, Spanish, Romanian and Russian.
Quick start
composer require "packstub/session-replay:^1.0@beta"
php artisan session-replay:install
Put the recorder in the layouts you want recorded:
@sessionReplay
</body>
Decide who may watch, in the app/Providers/SessionReplayServiceProvider.php the installer published:
use Illuminate\Support\Facades\Gate;
use Packstub\SessionReplay\Models\ReplaySession;
Gate::define('viewSessionReplay', function ($user, ?ReplaySession $session = null): bool {
return $user->is_admin;
});
Schedule the clean-up in routes/console.php:
use Illuminate\Support\Facades\Schedule;
Schedule::command('session-replay:prune')->daily();
Sign in, click around, then open /session-replay.
How it works
- Recorder.
@sessionReplayrenders a small config object and a deferred script. The script records the DOM and what happens to it with rrweb, one recording per browser tab, continued across page loads until the tab sits idle. - Signed token. When the page renders, the server signs who is signed in, the workspace, an impersonator and your own properties with the app key. The recorder sends that token back with every upload, so the ingest endpoint needs no session, no cookie and no CSRF token.
- Ingest. Every few seconds the recorder uploads a gzip batch with a small index next to it (markers, counts, the stylesheets the batch references). The server stores the file and updates the index; it never parses the events.
- Storage. Chunks go to
sessions/{id}/{seq}.json.gzon your disk, stylesheets toassets/under the hash of their content, the index toreplay_sessions,replay_chunks,replay_markersandreplay_assets. - Viewer.
/session-replaylists recordings; the player loads the manifest, the chunks and the stylesheets through routes that check theviewSessionReplaygate for that recording on every request.
Privacy defaults
| Default | Setting |
|---|---|
| Every input masked, passwords always | privacy.mask_all_inputs |
| Guests are not recorded | guests |
| No IP address stored | not configurable |
Livewire component state (wire:snapshot) never enters a recording |
size.strip_attributes |
| Recordings deleted after 30 days | retention.days |
Nobody can watch outside local until the gate exists |
viewSessionReplay |
See Privacy for masking, consent and wording for your privacy policy.
Documentation
| Guide | What it covers |
|---|---|
| Installation | Requirements, the install command, the directive, the gate, the scheduler |
| Recording | The directive and its options, who is recorded, sessions and sampling, markers, Livewire, CSP |
| Privacy | What is recorded, masking and blocking, consent, retention, policy wording |
| Watching replays | The gate, the built-in viewer, the player component, models and scopes |
| Storage | Disk layout, tables, multi-tenant apps, sizes and limits, pruning |
| Error tracking | The recording's id and URL in Laravel's Context |
| Configuration | Every key in config/session-replay.php |
In a Filament panel
packstub/filament-session-replay puts the sessions inside a Filament v5 panel: a filterable resource, the player with timeline tabs, a relation manager for your users, masking declared on the form field. It requires this package and records through it.
Alongside other tools
PostHog, Sentry, Microsoft Clarity and OpenReplay are great choices for product analytics, error monitoring and replay as a platform. This package is for replay inside your own app, next to your own models, on your own storage. They work well together.
Testing and development
composer test # Pest
composer lint # Pint
npm test # the recorder's pure functions
npm run build # resources/js -> resources/dist
composer serve # a page to record and the viewer, on :8000
Credits
- rrweb (MIT) records and replays the DOM.
- web-vitals (Apache-2.0) measures LCP, INP and CLS.
License
MIT. See LICENSE.md.
Related Packages
A powerful Laravel debugging tool with real-time monitoring, query debugging, an...
A portable Laravel customer support / helpdesk engine — tickets, threaded replie...
A beautiful dashboard for managing Laravel DevLogger records with IDE integratio...
Self-hosted Laravel translation manager for the TALL stack: edit, sync, import/e...