Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/phoenixframework/phoenix_live_view/llms.txt

Use this file to discover all available pages before exploring further.

LiveView emits comprehensive telemetry events throughout its lifecycle, allowing you to monitor performance, track errors, and gather metrics.

Event Overview

LiveView emits telemetry events for:
  • LiveView lifecycle callbacks (mount, handle_params, handle_event, render)
  • LiveComponent lifecycle callbacks (update, handle_event)
  • Component destruction
Each callback typically has three events: :start, :stop, and :exception.

LiveView Events

Mount Events

[:phoenix, :live_view, :mount, :start]

Dispatched immediately before mount/3 is invoked. Measurement:
%{system_time: System.monotonic_time()}
Metadata:
%{
  socket: Phoenix.LiveView.Socket.t(),
  params: unsigned_params | :not_mounted_at_router,
  session: map,
  uri: String.t() | nil
}

[:phoenix, :live_view, :mount, :stop]

Dispatched when mount/3 completes successfully. Measurement:
%{duration: native_time}
Metadata:
%{
  socket: Phoenix.LiveView.Socket.t(),
  params: unsigned_params | :not_mounted_at_router,
  session: map,
  uri: String.t() | nil
}

[:phoenix, :live_view, :mount, :exception]

Dispatched when an exception is raised in mount/3. Measurement:
%{duration: native_time}
Metadata:
%{
  socket: Phoenix.LiveView.Socket.t(),
  kind: atom,
  reason: term,
  params: unsigned_params | :not_mounted_at_router,
  session: map,
  uri: String.t() | nil
}

Handle Params Events

[:phoenix, :live_view, :handle_params, :start]

Dispatched immediately before handle_params/3 is invoked. Measurement:
%{system_time: System.monotonic_time()}
Metadata:
%{
  socket: Phoenix.LiveView.Socket.t(),
  params: unsigned_params,
  uri: String.t()
}

[:phoenix, :live_view, :handle_params, :stop]

Dispatched when handle_params/3 completes successfully. Measurement:
%{duration: native_time}

[:phoenix, :live_view, :handle_params, :exception]

Dispatched when an exception is raised in handle_params/3. Metadata includes: kind, reason, and other standard fields.

Handle Event Events

[:phoenix, :live_view, :handle_event, :start]

Dispatched immediately before handle_event/3 is invoked. Metadata:
%{
  socket: Phoenix.LiveView.Socket.t(),
  event: String.t(),
  params: unsigned_params
}

[:phoenix, :live_view, :handle_event, :stop]

Dispatched when handle_event/3 completes successfully.

[:phoenix, :live_view, :handle_event, :exception]

Dispatched when an exception is raised in handle_event/3.

Render Events

[:phoenix, :live_view, :render, :start]

Dispatched immediately before render/1 is invoked. Metadata:
%{
  socket: Phoenix.LiveView.Socket.t(),
  force?: boolean,
  changed?: boolean
}

[:phoenix, :live_view, :render, :stop]

Dispatched when render/1 completes successfully. Measurement:
%{duration: native_time}

[:phoenix, :live_view, :render, :exception]

Dispatched when an exception is raised in render/1.

LiveComponent Events

Update Events

[:phoenix, :live_component, :update, :start]

Dispatched immediately before update/2 or update_many/1 is invoked. Metadata:
%{
  socket: Phoenix.LiveView.Socket.t(),
  component: atom,
  assigns_sockets: [{map(), Phoenix.LiveView.Socket.t()}]
}
For update/2, this might dispatch one event for multiple calls.

[:phoenix, :live_component, :update, :stop]

Dispatched when update/2 or update_many/1 completes successfully. Metadata:
%{
  socket: Phoenix.LiveView.Socket.t(),
  component: atom,
  assigns_sockets: [{map(), Phoenix.LiveView.Socket.t()}],
  sockets: [Phoenix.LiveView.Socket.t()]
}
The sockets metadata contains the updated sockets.

[:phoenix, :live_component, :update, :exception]

Dispatched when an exception is raised in update/2 or update_many/1.

Handle Event Events

[:phoenix, :live_component, :handle_event, :start]

Dispatched immediately before handle_event/3 is invoked on a component. Metadata:
%{
  socket: Phoenix.LiveView.Socket.t(),
  component: atom,
  event: String.t(),
  params: unsigned_params
}

[:phoenix, :live_component, :handle_event, :stop]

Dispatched when component handle_event/3 completes successfully.

[:phoenix, :live_component, :handle_event, :exception]

Dispatched when an exception is raised in component handle_event/3.

Destroyed Event

[:phoenix, :live_component, :destroyed]

Dispatched after a LiveComponent is destroyed. No measurement. Metadata:
%{
  socket: Phoenix.LiveView.Socket.t(),
  component: atom,
  cid: integer(),
  live_view_socket: Phoenix.LiveView.Socket.t()
}

Setting Up Telemetry

Basic Telemetry Handler

Attach a handler in your application start:
# lib/my_app/application.ex
def start(_type, _args) do
  :telemetry.attach_many(
    "my-app-telemetry",
    [
      [:phoenix, :live_view, :mount, :start],
      [:phoenix, :live_view, :mount, :stop],
      [:phoenix, :live_view, :mount, :exception]
    ],
    &MyApp.Telemetry.handle_event/4,
    nil
  )
  
  # ... rest of your application setup
end

Handler Implementation

# lib/my_app/telemetry.ex
defmodule MyApp.Telemetry do
  require Logger

  def handle_event([:phoenix, :live_view, :mount, :start], measurements, metadata, _config) do
    Logger.info("LiveView mounting: #{inspect(metadata.socket.view)}")
  end

  def handle_event([:phoenix, :live_view, :mount, :stop], measurements, metadata, _config) do
    duration_ms = System.convert_time_unit(measurements.duration, :native, :millisecond)
    Logger.info("LiveView mounted in #{duration_ms}ms: #{inspect(metadata.socket.view)}")
  end

  def handle_event([:phoenix, :live_view, :mount, :exception], measurements, metadata, _config) do
    Logger.error("""
    LiveView mount failed: #{inspect(metadata.socket.view)}
    Reason: #{inspect(metadata.reason)}
    Kind: #{metadata.kind}
    """)
  end
end

Common Use Cases

Performance Monitoring

Track slow LiveView operations:
def handle_event([:phoenix, :live_view, :mount, :stop], %{duration: duration}, metadata, _) do
  duration_ms = System.convert_time_unit(duration, :native, :millisecond)
  
  if duration_ms > 1000 do
    Logger.warning("""
    Slow mount detected: #{inspect(metadata.socket.view)}
    Duration: #{duration_ms}ms
    URI: #{metadata.uri}
    """)
  end
end

Error Tracking

Send exceptions to external monitoring services:
def handle_event([:phoenix, :live_view | _] = event, _measurements, metadata, _config) do
  if List.last(event) == :exception do
    Sentry.capture_exception(
      metadata.reason,
      stacktrace: metadata.stacktrace,
      extra: %{
        live_view: inspect(metadata.socket.view),
        event: event
      }
    )
  end
end

Metrics Collection

Collect metrics with Telemetry.Metrics:
# lib/my_app/telemetry.ex
def metrics do
  [
    # LiveView mount duration
    summary("phoenix.live_view.mount.duration",
      unit: {:native, :millisecond},
      tags: [:view]
    ),
    
    # Event handling duration
    summary("phoenix.live_view.handle_event.duration",
      unit: {:native, :millisecond},
      tags: [:view, :event]
    ),
    
    # Render duration
    summary("phoenix.live_view.render.duration",
      unit: {:native, :millisecond},
      tags: [:view]
    ),
    
    # Exception count
    counter("phoenix.live_view.mount.exception.count",
      tags: [:view]
    )
  ]
end

Adding Custom Tags

Extract useful information for grouping:
def handle_event(event, measurements, metadata, _config) do
  tags = %{
    view: inspect(metadata.socket.view),
    connected: Phoenix.LiveView.connected?(metadata.socket)
  }
  
  :telemetry.execute(event ++ [:custom], measurements, Map.merge(metadata, tags))
end

Integration with Monitoring Services

AppSignal

Appsignal.Telemetry.attach([
  [:phoenix, :live_view, :mount, :start],
  [:phoenix, :live_view, :mount, :stop],
  [:phoenix, :live_view, :mount, :exception]
])

Prometheus

TelemetryMetricsPrometheus.init(
  metrics: MyApp.Telemetry.metrics(),
  port: 9568
)

StatsD

TelemetryMetricsStatsd.start_link(
  metrics: MyApp.Telemetry.metrics(),
  host: "localhost",
  port: 8125
)

Best Practices

  1. Filter events: Only attach handlers for events you need
  2. Use tags: Add meaningful tags to group and filter metrics
  3. Monitor performance: Track mount, event, and render durations
  4. Track exceptions: Send errors to monitoring services
  5. Set thresholds: Alert on slow operations or high error rates
  6. Use Telemetry.Metrics: For standardized metric definitions
  7. Test handlers: Ensure telemetry handlers don’t crash
  8. Keep handlers fast: Don’t block the LiveView process

Example: Complete Telemetry Setup

defmodule MyApp.Telemetry do
  use Supervisor
  import Telemetry.Metrics

  def start_link(arg) do
    Supervisor.start_link(__MODULE__, arg, name: __MODULE__)
  end

  def init(_arg) do
    children = [
      {:telemetry_poller, measurements: periodic_measurements(), period: 10_000},
      {TelemetryMetricsPrometheus, metrics: metrics()}
    ]

    Supervisor.init(children, strategy: :one_for_one)
  end

  def metrics do
    [
      # LiveView metrics
      summary("phoenix.live_view.mount.duration",
        unit: {:native, :millisecond},
        tags: [:view, :connected]
      ),
      summary("phoenix.live_view.handle_event.duration",
        unit: {:native, :millisecond},
        tags: [:view, :event]
      ),
      summary("phoenix.live_view.render.duration",
        unit: {:native, :millisecond},
        tags: [:view]
      ),
      
      # Exception counters
      counter("phoenix.live_view.mount.exception.count", tags: [:view]),
      counter("phoenix.live_view.handle_event.exception.count", tags: [:view, :event]),
      
      # LiveComponent metrics
      summary("phoenix.live_component.update.duration",
        unit: {:native, :millisecond},
        tags: [:component]
      ),
      counter("phoenix.live_component.destroyed.count", tags: [:component])
    ]
  end

  defp periodic_measurements do
    []
  end
end

Debugging with Telemetry

Use telemetry events for debugging in development:
if Mix.env() == :dev do
  :telemetry.attach_many(
    "debug-telemetry",
    [
      [:phoenix, :live_view, :mount, :start],
      [:phoenix, :live_view, :handle_event, :start]
    ],
    fn event, measurements, metadata, _config ->
      IO.puts("""
      Event: #{inspect(event)}
      View: #{inspect(metadata.socket.view)}
      Measurements: #{inspect(measurements)}
      """)
    end,
    nil
  )
end

Build docs developers (and LLMs) love