The shared building blocks of the six report pages: the filter bar, stat tiles, the trend chart, and the ranked breakdown card.
The charts are CSS, not JavaScript
A module whose whole premise is "no client-side weight on your pages" would
be a strange place to pull in a charting library for its own admin. Every
visual here is divs with a percentage height or width — themed by daisyUI
variables, responsive without a resize listener, and readable in both light
and dark themes with no configuration. Values are exposed through title
attributes, so hovering still tells you the exact number.
Summary
Functions
A ranked list: a label and one or two counts per row, with each row's share drawn as a bar behind it. Column headers sit on top, in the same fixed-width columns as the numbers, and the title's (i) explains where the data comes from and what the columns count.
The label for a stored channel (referrer_medium) value.
The label for a stored browser or operating-system name: real names (Chrome, macOS) are shown as they are; the two placeholders the User-Agent parser stores are translated.
The standard explanation of a breakdown card's Visitors / Views columns.
Percentage change from previous to current, or nil when there is no
meaningful comparison (no previous data, or no previous period at all).
The label for a stored device class.
A short call to action shown when tracking is installed but off.
The period selector shared by every report page — plus the site selector, only when the app actually served more than one host (an app on one domain has nothing to choose), and the page-filter chip when one is active.
Formats a duration in seconds as 1m 05s.
Formats a millisecond duration.
Formats an integer with thousands separators.
Formats a percentage to one decimal place.
A timestamp for a list: the time alone for today, the date and time otherwise.
One hit described in words, with an icon — "Viewed page", "Clicked add_to_cart", "Left after 1m 05s" — for the live feed and session timelines.
A small (i) that opens an explanation — a card under the icon on wide screens, a full-width card on a phone. Opens and closes on the client, with no server round trip.
The label for an interaction name recorded by the client script.
A Reports.top_interactions/2 row as words: "Outbound link · github.com/x".
Top-interaction rows with their labels in words, for a breakdown card.
"N online" — people on the site now — linking to the Right now page.
"Newer" / "Older" paging under a list, with an optional summary between.
Either phx-click events (newer_event / older_event) or links
(newer_path / older_path, patched) move between pages.
The label for a period value: "7d" is "Last 7 days".
A titled card around a table or list, with an optional (i) explanation and actions on the right — the frame every report section shares.
Where a visit came from: the referring source, else its channel.
A list of visits (rows from Reports.sessions/2): when, who, where they
landed and left, how many pages, what they did, how long, where from. Each
row opens the visit's timeline. Cards on narrow screens.
A headline number, optionally with its change against the previous period
and an (i) explanation (the :info slot).
The top row of every report page: the filters on the left, the online
badge on the right. On the Right now page, pass no period (there is no
window to choose) and no live_path.
The trend chart — core's server-rendered SVG bar_chart, one bar per
bucket, with dates in a row beneath it that uses the chart's own slot
widths, so every date sits under its bar. Only every few buckets are
labelled (at most about seven), which keeps a month of days readable on a
phone. Hovering a bar shows its exact date and count.
A visit's visitor: the signed-in user's display name, or "Anonymous".
Functions
A ranked list: a label and one or two counts per row, with each row's share drawn as a bar behind it. Column headers sit on top, in the same fixed-width columns as the numbers, and the title's (i) explains where the data comes from and what the columns count.
labels names a vocabulary the row labels come from (:channel, :device)
so raw stored values ("organic", "desktop") are shown translated.
Attributes
id(:string) - needed for the (i) explanation. Defaults tonil.title(:string) (required)rows(:list) (required)icon(:string) - Defaults tonil.empty_message(:string) - Defaults tonil.label_header(:string) - Defaults tonil.metric_header(:string) - Defaults tonil.link(:string) - Defaults tonil.link_label(:string) - Defaults tonil.labels(:atom) - Defaults tonil.Must be one ofnil,:channel,:device, or:client.show_visitors(:boolean) - Defaults totrue.info_align(:string) - Defaults to"start". Must be one of"start", or"end".
Slots
info
The label for a stored channel (referrer_medium) value.
The label for a stored browser or operating-system name: real names (Chrome, macOS) are shown as they are; the two placeholders the User-Agent parser stores are translated.
The standard explanation of a breakdown card's Visitors / Views columns.
Percentage change from previous to current, or nil when there is no
meaningful comparison (no previous data, or no previous period at all).
The label for a stored device class.
A short call to action shown when tracking is installed but off.
Attributes
settings_path(:string) (required)
The period selector shared by every report page — plus the site selector, only when the app actually served more than one host (an app on one domain has nothing to choose), and the page-filter chip when one is active.
Emits phx-change="filter" with period, site and path params.
Attributes
id(:string) - Defaults to"web-analytics-filter".period(:string) (required)site(:string) - Defaults tonil.sites(:list) - Defaults to[].path(:string) - the active path filter, if any. Defaults tonil.base_path(:string) - this report's URL, to clear the path filter. Defaults tonil.
Formats a duration in seconds as 1m 05s.
iex> PhoenixKitWebAnalytics.Web.Components.format_duration(65.4)
"1m 05s"
Formats a millisecond duration.
Formats an integer with thousands separators.
iex> PhoenixKitWebAnalytics.Web.Components.format_number(1234567)
"1,234,567"
Formats a percentage to one decimal place.
@spec format_time(DateTime.t() | NaiveDateTime.t() | nil, DateTime.t() | nil) :: String.t()
A timestamp for a list: the time alone for today, the date and time otherwise.
One hit described in words, with an icon — "Viewed page", "Clicked add_to_cart", "Left after 1m 05s" — for the live feed and session timelines.
Attributes
hit(:map) (required)
A small (i) that opens an explanation — a card under the icon on wide screens, a full-width card on a phone. Opens and closes on the client, with no server round trip.
Attributes
id(:string) (required)title(:string) (required)align(:string) - Defaults to"start". Must be one of"start", or"end".
Slots
inner_block(required)
The label for an interaction name recorded by the client script.
A Reports.top_interactions/2 row as words: "Outbound link · github.com/x".
Top-interaction rows with their labels in words, for a breakdown card.
"N online" — people on the site now — linking to the Right now page.
Attributes
count(:integer) (required)path(:string) - where the badge links; nil on the Right now page itself. Defaults tonil.
"Newer" / "Older" paging under a list, with an optional summary between.
Either phx-click events (newer_event / older_event) or links
(newer_path / older_path, patched) move between pages.
Attributes
newer?(:boolean) (required)older?(:boolean) (required)newer_event(:string) - Defaults tonil.older_event(:string) - Defaults tonil.newer_path(:string) - Defaults tonil.older_path(:string) - Defaults tonil.summary(:string) - Defaults tonil.
The label for a period value: "7d" is "Last 7 days".
A titled card around a table or list, with an optional (i) explanation and actions on the right — the frame every report section shares.
Attributes
id(:string) (required)title(:string) (required)icon(:string) - Defaults tonil.info_align(:string) - Defaults to"start". Must be one of"start", or"end".class(:any) - Defaults tonil.
Slots
infoactionsinner_block(required)
Where a visit came from: the referring source, else its channel.
A list of visits (rows from Reports.sessions/2): when, who, where they
landed and left, how many pages, what they did, how long, where from. Each
row opens the visit's timeline. Cards on narrow screens.
Attributes
id(:string) (required)sessions(:list) (required)names(:map) - Defaults to%{}.now(:any) - Defaults tonil.empty_message(:string) - Defaults tonil.
A headline number, optionally with its change against the previous period
and an (i) explanation (the :info slot).
Attributes
id(:string) (required)label(:string) (required)value(:string) (required)delta(:float) - Defaults tonil.delta_good(:atom) - Defaults to:up. Must be one of:up, or:down.info_align(:string) - Defaults to"start". Must be one of"start", or"end".
Slots
info
The top row of every report page: the filters on the left, the online
badge on the right. On the Right now page, pass no period (there is no
window to choose) and no live_path.
Attributes
period(:string) - Defaults tonil.site(:string) - Defaults tonil.sites(:list) - Defaults to[].path(:string) - Defaults tonil.base_path(:string) - Defaults tonil.online(:integer) (required)live_path(:string) - Defaults tonil.
The trend chart — core's server-rendered SVG bar_chart, one bar per
bucket, with dates in a row beneath it that uses the chart's own slot
widths, so every date sits under its bar. Only every few buckets are
labelled (at most about seven), which keeps a month of days readable on a
phone. Hovering a bar shows its exact date and count.
Attributes
id(:string) - Defaults to"web-analytics-trend".series(:list) (required)metric(:atom) - Defaults to:pageviews. Must be one of:pageviews, or:visitors.bucket(:atom) - Defaults to:day.
A visit's visitor: the signed-in user's display name, or "Anonymous".