PhoenixKitWebAnalytics.Plug (PhoenixKitWebAnalytics v0.2.0)

Copy Markdown View Source

Records one page view per HTML response — the whole tracker, server-side.

Add it once to the host's browser pipeline:

# lib/my_app_web/router.ex
pipeline :browser do
  # … existing plugs …
  plug PhoenixKitWebAnalytics.Plug
end

That's the entire installation. No script tag, no client-side bundle, no cookie, and nothing added to the rendered page — pages stay byte-for-byte what they were.

Cost to a request

The plug does three cheap things in the request process: a method/path check, one ETS read for settings, and register_before_send/2. When the response is on its way out it builds a map and hands it to PhoenixKitWebAnalytics.Collector, which does the settings-dependent enrichment, the session-stitch query, and the insert in a supervised task. No database work happens while the client is waiting.

What is skipped

Anything that isn't a person looking at a page:

  • non-GET requests, and non-2xx responses (a redirect isn't a page view)
  • responses that aren't text/html, so assets, JSON APIs, and file downloads never appear in reports
  • paths matching the exclusion patterns in settings (/admin* by default)
  • requests sending DNT: 1 or Sec-GPC: 1, when web_analytics_respect_dnt is on (it is by default)
  • automated User-Agents, unless web_analytics_track_bots is on
  • anything explicitly marked with skip/1

Options

  • :exclude — extra path patterns on top of the ones in settings, e.g. plug PhoenixKitWebAnalytics.Plug, exclude: ["/healthz", "/internal*"]. A trailing * makes a pattern a prefix match.

Client IP

conn.remote_ip is used as visitor-hash input (and only that — no IP is ever stored). Behind a proxy or load balancer that is the proxy's address, which would collapse every visitor into one. The right fix is a plug that rewrites remote_ip from the forwarding headers your infrastructure actually controls — remote_ip — placed before this one in the pipeline. Failing that:

config :phoenix_kit_web_analytics, trust_x_forwarded_for: true

reads the first entry of X-Forwarded-For. That header is client-settable, so only turn it on when something upstream is guaranteed to overwrite it.

Summary

Functions

Marks a request as not-to-be-tracked.

Whether this request has been marked to skip tracking.

Functions

skip(conn)

@spec skip(Plug.Conn.t()) :: Plug.Conn.t()

Marks a request as not-to-be-tracked.

Useful for endpoints that render HTML but aren't pages — a preview iframe, a health check that returns a status page, a LiveView upload target:

conn |> PhoenixKitWebAnalytics.Plug.skip() |> render("preview.html")

Also honoured when set before this plug runs, e.g. from an earlier plug.

skipped?(conn)

@spec skipped?(Plug.Conn.t()) :: boolean()

Whether this request has been marked to skip tracking.