Phoenix
Add Rybbit analytics to your Phoenix app
Phoenix renders every page inside the root layout, lib/my_app_web/components/layouts/root.html.heex, which owns the <html> and <head> tags, so the snippet goes there. Read the site ID from application config set in config/runtime.exs, so it comes from an environment variable at boot and stays out of the template.
Get your tracking snippet
In your Rybbit dashboard, open Site Settings → Tracking Script and copy your snippet. It looks like this:
<script src="https://app.rybbit.io/api/script.js?siteId=YOUR_SITE_ID" defer></script>YOUR_SITE_ID is the numeric ID of your site. If you self-host Rybbit, app.rybbit.io is the domain of your own instance.
Add the snippet to Phoenix
Configure the site ID
config/runtime.exs runs when the app boots, including inside a release, so it is the right place to read environment variables. Add a :rybbit key for your app (replace :my_app with your OTP app name):
config :my_app, :rybbit,
instance_url: System.get_env("RYBBIT_INSTANCE_URL", "https://app.rybbit.io"),
site_id: System.get_env("RYBBIT_SITE_ID")Then set the variables where the app runs:
export RYBBIT_INSTANCE_URL=https://app.rybbit.io
export RYBBIT_SITE_ID=YOUR_SITE_IDExpose the config to the layout
Templates in lib/my_app_web/components/layouts/ are embedded into the MyAppWeb.Layouts module, so a function defined there is callable from root.html.heex. Add one that returns the config:
defmodule MyAppWeb.Layouts do
use MyAppWeb, :html
embed_templates "layouts/*"
def rybbit_config, do: Application.get_env(:my_app, :rybbit, [])
endAdd the tag to the root layout
Open lib/my_app_web/components/layouts/root.html.heex and add the tag inside <head>, after the existing app.css and app.js tags:
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="csrf-token" content={get_csrf_token()} />
<.live_title suffix=" · Phoenix Framework">{assigns[:page_title] || "MyApp"}</.live_title>
<link phx-track-static rel="stylesheet" href={~p"/assets/app.css"} />
<script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}></script>
<script
:if={rybbit_config()[:site_id]}
src={"#{rybbit_config()[:instance_url]}/api/script.js?siteId=#{rybbit_config()[:site_id]}"}
defer
></script>
</head>The :if attribute skips the tag when RYBBIT_SITE_ID is unset, so development and test environments are not tracked unless you set the variable there.
LiveView navigation
<.link navigate>, <.link patch>, push_navigate/2 and push_patch/2 change the URL with history.pushState (or replaceState when replace: true) and keep the root layout, including its <head>, in place. The Rybbit script hooks history.pushState and history.replaceState and listens for popstate and hashchange, so each live navigation is tracked as a pageview while SPA Navigation is enabled in your site settings (the default). No phx: event listener is needed. A regular <.link href> does a full page load, which the script also tracks.
Verify installation
Open your live site in a new tab and click through a few pages. Within a few seconds the pageviews appear in the Rybbit dashboard.
If nothing shows up:
- View the page source and search for
script.js?siteId=to confirm the snippet is on the page. - Open the browser Network tab and check that
script.jsreturns200and thatPOSTrequests go to/api/track. - Disable ad blockers, or set up a proxy so the script loads from your own domain.
- See the script troubleshooting guide for other common causes.
Troubleshooting
- Tag missing:
config/runtime.exsis evaluated at boot, so restart the app or release after changingRYBBIT_SITE_ID. Check withApplication.get_env(:my_app, :rybbit)iniex -S mix. - Content Security Policy: if you set a
content-security-policyheader in a plug, add your Rybbit host toscript-srcandconnect-src, or proxy the script through your own domain. - Self-hosted instance: set
RYBBIT_INSTANCE_URLto your own domain without a trailing slash; the layout appends the script path to it.
Next steps
- Track custom events such as signups, purchases and button clicks.
- Identify users to connect sessions to accounts.
- Proxy the script through your own domain to bypass ad blockers.
- Script attributes let you skip or mask URLs and tag events.