Pixelex.Plug.Context (Pixelex v0.1.0)

Copy Markdown View Source

A Plug.Conn turned into a pipeline context.

This is where pixelex's server-first stance pays off: the IP, user agent, referrer, language and privacy headers are all already here, on every request, before any JavaScript has run. Nothing needs to be asked of the browser to produce a complete analytics record — the tracker adds screen size and engagement, and nothing else that matters.

Client IP behind a proxy

conn.remote_ip is the load balancer's address on Fly, Heroku, Cloudflare and behind nginx — so every visitor hashes to the same id and a site sees one visitor forever. Configure the header the proxy actually sets:

config :pixelex, client_ip_header: "fly-client-ip"

x-forwarded-for is supported and its left-most entry is taken. That entry is client-controlled, so it is only trusted when explicitly configured; the default reads conn.remote_ip and is wrong-but-safe rather than forgeable.

Country

Taken from a CDN header when one is present — cf-ipcountry, fly-client-country, x-vercel-ip-country are checked by default, and :country_header overrides. No GeoIP database is bundled: the hosts these apps run on already do the lookup, and shipping a 70MB database plus its licence to duplicate that would be a poor trade.

Summary

Functions

Build a context from a connection.

The visitor's real IP, honouring a configured proxy header.

Consent signals: the privacy headers, plus whatever the host's banner recorded.

Functions

build(conn, opts \\ [])

@spec build(
  Plug.Conn.t(),
  keyword()
) :: map()

Build a context from a connection.

Options

  • :site_id — required unless resolvable from the host
  • :render — defaults to :dead
  • :url, :referrer — override what the connection says, for the ingest endpoint where the real page is in the payload rather than the request

client_ip(conn)

@spec client_ip(Plug.Conn.t()) :: String.t() | nil

The visitor's real IP, honouring a configured proxy header.

consent(conn, opts \\ [])

@spec consent(
  Plug.Conn.t(),
  keyword()
) :: Pixelex.Consent.signals()

Consent signals: the privacy headers, plus whatever the host's banner recorded.