Pass User Agent info to your LiveView

A Phoenix called The User Agent holding a magnifier
Image by Annie Ruygt

In this article we talk about getting User Agent inside your LiveView. Fly.io is a great place to run your Phoenix LiveView applications! Check out how to get started!

Here’s a quick recipe. Say your LiveView needs to show something based on the device your user is on such as Mac or Windows. You can parse that from your User Agent header, in fact LiveView already gives you a simple method for that: get_connect_info(socket, :user_agent).

The get_connect_info/2 function allows you to retrieve connection information that is only available during the mount lifecycle, such as header or IP information.

Here’s a simple LiveView that just shows your current device based on your user agent. You can use the ua_parser library to do the weird stuff.

defmodule GetUserAgentWeb.UserAgentLive do
  use GetUserAgentWeb, :live_view

  def render(assigns) do
    ~H"""
    <div class="text-xl">Device: </div>
    """
  end

  def mount(_params, _session, socket) do
    device = 
      case UAParser.parse(get_connect_info(socket, :user_agent)) do
        %UAParser.UA{device: %UAParser.Device{family: fam}} -> fam
        _ -> "I don't know your device"
      end

    {:ok, assign(socket, device: device)}
  end
end

But there’s a catch!

Why your device appears and disappears immediately, you ask? Let’s go through how LiveViews render.

A sequence of 5 states connected by arrows: the first state is your user opening the page doing a HTTP request, the second state is LiveView rendering a disconnected mount, the third state is the user seeing the app and requesting to be connected to the WebSocket, the fourth state is LiveView rendering a connected version and replying to the user, and the fifth and final state is the user having a dynamic web page.

Run your LiveViews on Fly.io

You can host your LiveView form apps here on Fly.io and get free SSL so users know only your server knows their User Agent.

Try Fly for free

User agents come as HTTP headers so when LiveView first receive an HTTP request that information is already available, the server will reply with a simple HTML response and the device will be rendered. As for WebSockets, they work like this: your browser does a simple HTTP request to a server but the server replies telling that this request will be upgraded to an WebSocket.

During the socket upgrade you lose your User Agent—The WebSocket connection doesn’t carry this info—so this second render clears the device value from the screen. You need to tell Phoenix to store it under your socket state so you can use it later. Go to your endpoint.ex file and let’s edit it a little bit:

- socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]
+ socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [:user_agent, session: @session_options]]

You just added :user_agent to the WebSocket config and now everything should just work! Don’t forget to restart your server; endpoint.ex doesn’t get reloaded automatically.