One analytics hit — a page view or a custom event.
Rows are append-only: there is no updated_at and nothing ever updates an
event after insert. PhoenixKitWebAnalytics.Retention rolls old rows into
PhoenixKitWebAnalytics.Schemas.DailyStat and deletes them.
Identity is cookieless
There is no cookie, no local storage, and no raw IP address in this table.
visitor_id is a truncated SHA-256 of salt <> ip <> user_agent <> date
(see PhoenixKitWebAnalytics.Visitor) — it cannot be reversed to an IP, it
cannot be joined across days, and it changes when the daily salt rotates.
The exception is click_id: an ad platform's own identifier, kept when a
visit lands with one, which is pseudonymous and links to the platform's
user (see the README's Privacy section).
session_id is stitched server-side by
PhoenixKitWebAnalytics.Collector: an event reuses the visitor's previous
session when the previous hit is inside the session window, otherwise it
starts a new one.
Event types
"pageview"— one HTML response served, or one LiveView navigation"event"— a custom event reported throughPhoenixKitWebAnalytics.track_event/2or the beacon endpoint"interaction"— something the visitor did on a page: a LiveView event (event_nameis the event, e.g."add_to_cart") or a click reported by the optional client script (event_nameis"click","outbound"or"download",targetwhat was clicked)"leave"— the visitor left a page;engaged_msis how long it was open andscroll_depth(client script only) how far they scrolled
Tables are created by PhoenixKitWebAnalytics.Migrations, never by this
schema.
Summary
Functions
Changeset for a single hit.
Valid device_type values.
Valid event_type values.
Valid referrer_medium values.
Types
@type t() :: %PhoenixKitWebAnalytics.Schemas.Event{ __meta__: term(), browser: term(), browser_version: term(), city: term(), click_id: term(), click_param: term(), country_code: term(), device_type: term(), duration_ms: term(), engaged_ms: term(), event_name: term(), event_type: term(), inserted_at: term(), is_bot: term(), language: term(), metadata: term(), os: term(), os_version: term(), page_title: term(), path: term(), referrer: term(), referrer_medium: term(), referrer_source: term(), region: term(), scroll_depth: term(), session_id: term(), session_start: term(), site: term(), status: term(), target: term(), user_uuid: term(), utm_campaign: term(), utm_content: term(), utm_medium: term(), utm_source: term(), utm_term: term(), uuid: term(), visitor_id: term() }
Functions
@spec changeset(t(), map()) :: Ecto.Changeset.t()
Changeset for a single hit.
Long free-text fields are truncated rather than rejected — an over-long
page_title or referrer from the wild must never cost us the whole event.
@spec device_types() :: [String.t()]
Valid device_type values.
@spec event_types() :: [String.t()]
Valid event_type values.
@spec referrer_mediums() :: [String.t()]
Valid referrer_medium values.