Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Session Replay Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

Build vs. buy on session replay. Session replay normally arrives as a per-seat, per-session SaaS line (LogRocket, FullStory, Hotjar, Sentry Replay). This package turns that into "install a Composer package and own the storage": MIT licensed, no per-session meter, recordings on your own disk with an index in your own database. The buy-vs-build question reframes from licensing cost to a small, well-understood ops cost — a disk, a table set, a retention policy, a scheduled PruneCommand. That is a defensible buy nothing call for a Laravel monolith whose requirement is "show me what the user saw when this broke," not "give me a growth analytics platform." Beta.5 improves the economics of that call on Livewire apps: a wire:navigate page now lands as a fresh snapshot rather than one change adding every node of the new page — roughly a third less data on disk and about a third less main-thread blocking in the maintainer's navigation lab — and late-loading stylesheets are now stored once by hash instead of being re-sent inline on every page view. If you sized storage or client cost from an earlier version, the estimate is now pessimistic.

A privacy and data-residency roadmap unlock. This is the strongest product lever. Recordings never leave your infrastructure; the ingest endpoint trusts only a ContextToken signed with the app key at render time, so no session, cookie, CSRF token, or third-party JS origin is involved; stylesheets are content-addressed by SHA-256 and verified on upload; gzip is inflated once with a ceiling so a malicious upload can't bomb the viewer's browser. The stated policy — privacy defaults only tighten within a major, every privacy control stays in the free package — is a commitment you can quote in a security review. That is what makes session replay adoptable for products that previously couldn't have it: health-adjacent, fintech-adjacent, EU-resident, or anything under a customer contract that forbids new subprocessors.

Scoping the "why did this break?" workflow, and saying no to analytics. The marker set is opinionated toward support and debugging: errors, console output, failed Livewire requests, web vitals, rage clicks, navigation, custom markers. That maps to a concrete roadmap item — attach a replay link to every support ticket and exception report — and a concrete non-goal — no funnels, no heatmaps, no A/B analysis. Use it to redirect analytics requests to the tool that actually owns them.

Access control as a product decision, not a vendor setting. The viewSessionReplay gate is enforced on the data routes as well as the viewer, with the recording bound as the gate argument. So you can ship replay to a support role without shipping raw screens company-wide, express per-tenant or per-recording rules in code you already own, and treat "who can watch whom" as a reviewable policy artifact. Note the inverse: a permissive gate is a total-disclosure failure, so deny-by-default plus a 403 integration test on every data route is a launch requirement, not a nice-to-have.

A real roadmap fork: core vs. panel. The core package imports nothing from Filament\ or Livewire\; the panel UI is a separate sibling package that requires it. Adopt core alone when replay lives behind your own Blade page and gate; add the Filament package when ops already lives in a panel. This is a strategic benefit — the core is adoptable by teams who will never run Filament — with one hazard: the two share the Packstub\SessionReplay\ namespace via merged PSR-4 directories, so if you install both, pin and upgrade them together.

Instrumentation reach without a second SDK. The recorder detects Livewire in the browser and marks failed Livewire requests; HasSessionReplays and the ReplaySessionStarted event give you model hooks and a place to hang notification or ticketing logic; replay ids are pushed into Laravel's Context, so every log line correlates to a recording. That supports "link the replay to the domain object" (order, ticket, account) rather than "search by timestamp" — which is the difference between a debugging toy and a support workflow. Beta.5 sharpens the Livewire story: navigation is bracketed with pause/resume so the player can jump straight to any page without replaying the ones before it, a recording has one chunk row per page, custom markers and SessionReplay.mark() calls made during the swap are preserved, and the last page before tab close is no longer dropped when the swap was too large to flush. That makes the support experience — "open the ticket, jump to the failing page, watch from there" — materially better, not just cheaper. One planning detail: only a real page load is shared through snapshots.share_routes; a page reached via wire:navigate is never shared, even if recording started there, so don't model snapshot-sharing savings off navigation-heavy flows.

A line item for the risk register. Still pre-stable at 1.0.0-beta.5: a small install base, zero dependents, a single maintainer and namespace, docs not yet synced to the store, and a 1.x window in which config keys, migration names, route names, and the chunk format are frozen. Beta churn is real — beta.5 changes recording granularity (a chunk row per wire:navigate page) and how stylesheet text is stored, even though old recordings keep playing. Treat it as an early-adopter dependency: viable for internal tooling and support workflows; not yet something to build a customer-facing SLA on.

When to Consider This Package

Adopt when most of these hold:

  • The app is Laravel 12/13 on PHP 8.3+, and you're comfortable pinning a pre-1.0 package. Older Laravel or PHP 8.2 estates are blocked — treat that as a scoping gate, not a footnote.
  • Replay is for debugging and support, not growth analytics: you want "what happened in this session" attached to a ticket, not funnels or segment comparison.
  • You have a stated constraint that session data must not leave your infrastructure — data residency, a DPA that forbids new subprocessors, or an internal security bar.
  • You can own the operational tail: a filesystem disk, a database connection for the index tables, a retention policy, and a scheduled prune.
  • You want masking/redaction policy expressed in your own config and reviewed by your own security team, including a hard exclusion list for auth, checkout, admin, and health routes.
  • You have a mature authorization model you trust, because the gate is the product surface.
  • You're willing to verify the committed resources/dist bundle against resources/js at pin time — it executes on every recorded page from your own domain.

Livewire-specific: from beta.5 this is a good fit for a Livewire 3 app that leans on wire:navigate for an SPA-ish feel — navigation is recorded as snapshots, per-page chunks keep the player seekable, and payloads drop noticeably. Two things to check rather than assume: your snapshot-sharing plan can't include wire:navigate pages, and if a script of yours wraps console.error, the recorder keeps that wrapper in place across navigation, so verify your own console instrumentation still behaves.

Look elsewhere when:

  • You need managed infrastructure, an SLA, or no-on-call. This package makes you the operator; that is the trade, and it isn't free at scale.
  • You need native mobile or desktop replay, or replay across non-Laravel front ends. This is a browser recorder served by a Laravel controller.
  • You need analytics primitives — funnels, heatmaps, retention curves, session search at scale. Wrong data model, wrong tool.
  • You're at high volume and need hot-tier querying with long retention and no storage-lifecycle design. Disk-plus-index is simple and honest; it is not a data warehouse.
  • You need commercial support, a vendor-answered security questionnaire, or a named maintainer with a responsiveness commitment. Expect to read the source and run both packages' test suites after changes. MIT is your fork escape hatch.
  • You run a heavily scripted SPA with its own replay needs and won't take rrweb as the recorder. Also check CSP: the recorder is emitted as an inline script tag, so you'll need a nonce or hash path.
  • Recordings imply obligations you can't staff: encryption at rest, DSAR/deletion, and viewer access auditing are yours. The package ships pruning and a session-start event; gate logging is on you.

A useful middle path: pilot on an internal admin app or an internal-only tenant, where the blast radius of an early-version dependency is a few engineers and the gate naturally limits viewers. Measure support time saved, then decide on wider rollout.

How to Pitch It (Stakeholders)

To executives: We can have session replay — the "watch the session that broke" capability — without a vendor, a per-seat contract, or a new subprocessor. Recordings stay on our disk and in our database, access is governed by a gate we write and can review, and the license is MIT, so there's no per-session meter as usage grows. The trade is that we operate it: storage, retention, and pruning become ours — a small, well-understood ops surface for a Laravel app, converting an open-ended SaaS cost into a fixed infrastructure cost. The latest beta also cut recording size and client cost on our Livewire pages by roughly a third, so the storage line in this proposal is now conservative rather than optimistic. Recommendation: pilot on an internal surface, measure support time saved, then decide on rollout. Flag for the risk log that the package is early — pre-1.0, small install base, single maintainer, frozen formats landing in 1.x — so we pin the version and be ready to read the source.

To engineering: A thin, deliberately unopinionated package. rrweb in the browser, a signed-token ingest endpoint that needs no session or CSRF, gzipped chunks on a disk with a DB index, and a small gated viewer. The server never parses rrweb payloads — the browser sends the index alongside the events — so PHP cost stays flat per batch and a class of parser bugs disappears. No Filament or Livewire imports in the core; the panel integration is a separate package if we want it. Front-end assets are prebuilt and committed, served from our domain, so the app never builds or publishes anything. There's a prune command, a ReplaySessionStarted event, a HasSessionReplays trait, and replay ids in Context so logs correlate to recordings. Integration is roughly half a day: install, publish the provider stub, define the gate, configure a disk and the index connection, schedule the prune. Tests are Pest + Testbench with node --test over the pure JS functions.

Two things changed in beta.5 worth knowing before we pin: Livewire wire:navigate swaps are now bracketed (pause on livewire:navigating, resume on livewire:navigated or a five-second fallback) so each page arrives as its own snapshot and chunk row, and stylesheet text that arrives after serialization is deduplicated by hash instead of being re-uploaded per page view. That means better player seeking and less disk for navigation-heavy panels, and old recordings still play unchanged. Verify before commit: the CSP path for the inline recorder script, a test asserting 403 on every data route for an unprivileged user, and — if we plan to use snapshots.share_routes for storage savings — that we're not counting wire:navigate pages, which are never shared.

To security and legal: No third-party JavaScript is loaded and no recording data leaves our infrastructure. Ingest identity is a token signed with the app key at render time; the ingest route needs no cookies, no session, and no CSRF token, and identity is never keyed by IP. The viewer gate is enforced on data routes as well as pages, with the recording bound as the gate argument, so authorization is per-recording rather than per-route. Uploaded stylesheets are content-addressed and hash-verified, and gzip is inflated exactly once with a size ceiling so decompression bombs never reach the browser. Masking and redaction are configuration we own and can review line by line, and the project's stated policy is that privacy defaults only tighten within a major version and every privacy control stays in the free package. What we take on: encryption at rest, retention, DSAR/deletion, and access auditing for the viewer — we should scope those explicitly rather than assume the package covers them. Languages ship for en, de, es, ro, ru; additional strings are a contribution, not a fork.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log