Stickybeak Docs Dashboard Get early access

Backends

Phoenix

Phoenix analytics with Stickybeak starts by adding its script to your rendered pages; this guide shows you where it belongs and how to track page views, goals and purchase revenue.

Add the script

  1. Configure the site ID for production

    Copy the ID from Settings in the dashboard, set it as STICKYBEAK_SITE_ID where your release runs, and read it in the production branch of your runtime config:

    if config_env() == :prod do
      config :my_app, :stickybeak_site_id, System.get_env("STICKYBEAK_SITE_ID")
    end
  2. Add it to the root layout

    Put this before </head>:

    <script>window.stickybeak = window.stickybeak || function () { (window.stickybeak.q = window.stickybeak.q || []).push(arguments); };</script>
    <%= if site_id = Application.get_env(:my_app, :stickybeak_site_id) do %>
      <script
        defer
        data-site={site_id}
        data-domain="example.com"
        src="https://app.usestickybeak.com/_cfw/s.js"
      ></script>
    <% end %>

Check it's working

Publish first, then follow Verify your install.

Track goals

Give any button or link a data-goal attribute. See Custom goals.

<.link navigate={~p"/pricing"} data-goal="view_pricing">Pricing</.link>

Goals from a LiveView

Push an event from the server and pass it on in the browser. Add the listener once:

window.addEventListener("phx:stickybeak", (event) => {
  window.stickybeak(event.detail.name, event.detail.props);
});
def handle_event("save", %{"user" => params}, socket) do
  case Accounts.register_user(params) do
    {:ok, user} ->
      {:noreply,
       socket
       |> assign(:registered, true)
       |> push_event("stickybeak", %{name: "signup", props: %{plan: user.plan}})}

    {:error, changeset} ->
      {:noreply, assign(socket, form: to_form(changeset))}
  end
end

Goals after a controller redirect

For controller redirects, put the goal in the session and move it into assigns:

pipeline :browser do
  # ...the generated plugs...
  plug :stickybeak_goal
end

defp stickybeak_goal(conn, _opts) do
  case get_session(conn, :stickybeak_goal) do
    nil -> conn
    goal -> conn |> delete_session(:stickybeak_goal) |> assign(:stickybeak_goal, goal)
  end
end
conn
|> put_session(:stickybeak_goal, %{
  "name" => "purchase",
  "props" => %{"revenue" => Decimal.to_string(order.total), "currency" => order.currency, "order_id" => order.number}
})
|> redirect(to: ~p"/orders/#{order}/thanks")
<%= if goal = assigns[:stickybeak_goal] do %>
  <script>window.stickybeak(<%= raw(Jason.encode!(goal["name"], escape: :html_safe)) %>, <%= raw(Jason.encode!(goal["props"] || %{}, escape: :html_safe)) %>);</script>
<% end %>

Track purchases

Render window.stickybeak("purchase", { revenue, currency, order_id }) on the checkout confirmation page.

See Revenue.

Page changes

Nothing extra to do.

  • Navigation with replace: true replaces the history entry instead, so it isn't a new page view.
  • A patch that only changes query parameters (a filter, a sort order) isn't a new page view either, because the path is the same.

If it isn't working

  • Set the release variable in runtime.exs, not build-time prod.exs.

See Troubleshooting.