packstub/session-replay
Packstub Session Replay captures user session activity in Laravel applications and lets you replay those sessions step by step to reproduce bugs and diagnose issues. Simple to install and configure, it gives developers a clear view of what users experienced without guesswork.
Architecture fit
SessionReplay facade, config, migrations, Blade views, global + route middleware, an artisan command, and a provider stub published by session-replay:install. A Laravel-fluent team can reason about it without a specialist.Filament\ or Livewire\; panel UI is a separate sibling package. We can adopt the free package alone and serve the Blade viewer behind a gate, which is the right shape for an engineering-first rollout. The panel becomes a later, separable decision.ContextToken (user, tenant, impersonator, properties) signed with the app key at render time, so uploads need no session, cookie, or CSRF token. Correct for a fire-and-forget uploader; it does put the app key inside the ingest trust chain.AuthorizeViewer wraps viewer and data routes, with the recording bound as the gate argument. This is the single most important property to verify in our own review, because it is what lets us ship replay to support without shipping raw screens company-wide.wire:navigate swap is now recorded as a fresh snapshot (recorder pauses on livewire:navigating, resumes on livewire:navigated, with a 5s fallback) instead of one diff that re-adds every node. Architecturally this is the right call: it aligns the recording model with how Livewire actually swaps the DOM, and it makes a recording navigable page-by-page in the player. It also means the chunk model is now one chunk row per page for navigate-driven apps, not just per page load — a storage-and-schema consequence we must model, not just a UX nicety.<link>, or one appended by wire:navigate) is now hashed and stored once rather than inlined on every page view. The vendor reports a Lab page record going 25 KB → 17 KB. Treat that as a directional claim to re-measure on our markup, not a planning number.Integration feasibility
viewSessionReplay → configure a disk and the storage.connection database → schedule PruneCommand. Roughly half a day for a Laravel-fluent engineer on staging, with the caveats below. No front-end build or asset publishing; resources/dist is committed and served by ScriptController.SessionReplay::recorder() carrying config and the signed token. It implies an inline script, so it interacts with our CSP — confirm a nonce or hash path in the spike, before committing to a date.setTimeout fallback, console-wrapper preservation. Budget the review, and re-check that the recorder's masking path is untouched by the navigation pause (our read is that it is, but "we read it" is not acceptance criteria).Technical risk
resources/js/lib/process.js and rrweb options, with a stated policy that privacy defaults only tighten within a major. That policy is quotable to security review but does not substitute for enumerating recorded routes, confirming maskAllInputs and text-masking defaults, and maintaining a hard exclusion list (auth, checkout, admin, health checks).viewSessionReplay exposes every recording. Deny-by-default plus an integration test asserting 403 on every data route for an unprivileged user is mandatory acceptance criteria.PruneCommand and ReplaySessionStarted ship; an access audit trail still does not appear to, so gate logging is ours to build.livewire:navigated never fires and the timeout path is slow, or if a third-party script blocks the swap, we get a silent gap. Console markers and SessionReplay.mark() survive, so the gap is diagnosable — but only if support knows to look for it. Add "recording gap around navigation" to the triage runbook.snapshots.share_routes. Apps that lean on wire:navigate get less deduplication benefit than the config name implies; size the disk plan off measured data, not off the feature flag.node --test coverage, and this release is validated against a cross-package Livewire navigation run. That is a positive maintenance signal, not a vendor SLA. MIT remains the fork escape hatch.resources/dist is committed and executes on every recorded page from our domain. Diff it against resources/js at every pin, not just the first, and pin the rrweb version and license.Packstub\SessionReplay\ namespace via merged PSR-4 directories. This release's validation was in the Filament lab — one more reason to pin and upgrade the pair together if both are installed.Key questions
ContextToken lifetime — expiring, single-use, or bounded to a session id?recordWhen?livewire:navigating → livewire:navigated window, and what exactly is lost if the 5s fallback fires — is there a marker in the timeline indicating a gap?console?PruneCommand can target, and is there a supported path for deleting a single page or a single recording on DSAR request?Stack fit
wire:navigate transitions as clean per-page snapshots. That is exactly the class of bug our support queue struggles to reproduce, and the navigate path is where Livewire apps actually break.Migration path
composer update side-effect.Compatibility
Sequencing
wire:navigate flow end to end and inspect the resulting chunk rows and page boundaries.wire:navigate, and re-derive the disk plan. Do not carry the vendor's 25 KB → 17 KB Lab figure into a capacity commitment.Context correlation already in log lines. This is the step that produces the measurable outcome.packstub/filament-session-replay pinned to the same version.Maintenance
PruneCommand, and periodic dependency bumps. Small, well-understood surface for a Laravel team, but permanently ours — there is no vendor to escalate to.Support
SessionReplay.mark() across a navigation swap, which is our hook — write the runbook line now.Scaling
PruneCommand duration scales with rows, not just bytes.snapshots.share_routes savings do not extend to navigate-reached pages. Net effect on disk is app-specific; measure it.Failure modes
livewire:navigated never arrives. Mitigation: verify marker/console continuity in the spike, test the timeout path deliberately, document the symptom in the triage runbook.Ramp-up
wire:navigate and cross-version playback checks.How can I help you explore Laravel packages today?