PhoenixReplay 📹

Hex.pm Documentation

Session recording and replay for Phoenix LiveView. PhoenixReplay records what your LiveViews and LiveComponents did — events, navigation and assigns — and replays a session by re-rendering your own templates with the recorded assigns. No browser recording script, no DOM snapshots.

PhoenixReplay replaying a form session

mix igniter.install phoenix_replay

The installer mounts the dashboard at /dev/replay in development. Record a live session:

live_session :default, on_mount: [PhoenixReplay.Recorder] do
live "/checkout", CheckoutLive
end

Use your app, then open /dev/replay. To use the dashboard in production, mount it behind your own authentication:

scope "/admin" do
pipe_through [:browser, :require_admin]
phoenix_replay "/replay"
end

Why PhoenixReplay

Browser session recorders capture the DOM and ship every keystroke from the client. A LiveView already knows its state: its template is a function of its assigns. PhoenixReplay records assigns on the server, where they are produced, and replays them through the same template — so a replay shows exactly what the server rendered, a 30-second form session takes a few kilobytes, and nothing changes in your JavaScript.

See Why PhoenixReplay and How It Works.

Recording

Every connected LiveView in the live session is recorded, along with its LiveComponents — without changes to your views or components. Sessions without user interaction are discarded. Sample a share of sessions or tune limits per live session:

live_session :checkout,
on_mount: [{PhoenixReplay.Recorder, sample_rate: 0.1, max_events: 2_000}] do
live "/checkout", CheckoutLive
end

See the Recording guide and LiveComponents guide.

Privacy

Values of keys such as password, token and secret are replaced with "[FILTERED]" before anything is stored, through structs, changesets and forms. Plug in your own sanitizer to drop more:

defmodule MyApp.ReplaySanitizer do
@behaviour PhoenixReplay.Sanitizer
@impl true
def sanitize_assigns(assigns) do
assigns |> Map.drop([:current_user]) |> PhoenixReplay.Sanitizer.Default.sanitize_assigns()
end
@impl true
defdelegate sanitize_params(params), to: PhoenixReplay.Sanitizer.Default
end

See the Privacy and Security guide.

Dashboard

Browse, filter and replay recordings with a scrubber, keyboard controls and playback speeds. Filters live in the URL, so /admin/replay?event=checkout&within=24h is a shareable link. Restrict who sees what with an authorization module:

phoenix_replay "/replay",
on_mount: [{MyAppWeb.UserAuth, :ensure_admin}],
authorize: MyApp.ReplayAuthorization

The dashboard ships its own assets and loads your app's own Phoenix and LiveView clients, so it needs nothing from your asset pipeline. See the Dashboard guide.

Storage

Recordings are kept in compressed files by default, or in your database:

config :phoenix_replay,
storage: {PhoenixReplay.Storage.Ecto, repo: MyApp.Repo},
retention: [max_age: :timer.hours(24 * 7), max_count: 1_000]

See the Storage guide and the Configuration cheatsheet.

Example app

A Phoenix app with recording and the dashboard wired up lives in example/:

cd example
mix setup
mix phx.server

Documentation

Full documentation, guides and cheatsheets are available on HexDocs.

Development

mix deps.get
npm ci
npx playwright install chromium
mix ci

Part of Elixir Vibe

PhoenixReplay records LiveView sessions as assigns timelines, making every session replayable and every bug reproducible.

It is one building block of a larger stack — tools that make AI-generated software checkable: structural search, dependence analysis, duplication and slop detection, session replay, and ecosystem-wide code search. See the Elixir Vibe organization for the rest, and Building Blocks for the Future Web for the thesis, architecture, and roadmap that tie them together.

License

MIT © 2026 Danila Poyarkov