GoodAnalytics.Core.Audience (GoodAnalytics v0.1.1)

Copy Markdown View Source

One shared, tested audience-breakdown query surface for every consumer.

breakdown/3 returns rows of %{value: term(), <metrics...>} for a single dimension over a workspace + time window. Dimensions and metrics are declared once (data-driven) so there is no per-dimension copy-paste.

Grain (why some metrics are non-additive)

  • Event-grain dimensions (:device_type, :browser, :os, :source_platform, :source_medium, :source_campaign) group events by the event's own column — a device is the context of an interaction, not an attribute of the identity.
  • Person-grain :users counts DISTINCT coalesce(merged_into_id, id), so one cross-device person is counted in every device/browser/os bucket they were active in. "mobile users + desktop users" can therefore exceed total users — and that is correct (GA4 behaviour). :users is non-additive by design; an additive partition would be a separately named :primary_device_users metric, deferred until requested.
  • Session-grain metrics (:sessions, :bounce_rate, :avg_duration, :engaged_rate) aggregate ga_sessions. A session's device/source is its first event's, stored on the session row, so they group cleanly by s.device_type etc.

Metrics

metricgraindefinition
:eventseventcount(e.id)
:pageviewseventcount(e.id) FILTER (event_type = 'pageview')
:userspersoncount(DISTINCT coalesce(v.merged_into_id, v.id)) (non-additive)
:sessionssessioncount(s.id)
:bounce_ratesessionavg(s.is_bounce::int)
:avg_durationsessionavg(s.duration_seconds)
:engaged_ratesessionavg(s.is_engaged::int)

Usage

GoodAnalytics.Core.Audience.breakdown(workspace_id, :device_type,
  window: %{start_at: from, end_at: to},
  metrics: [:events, :users, :sessions, :bounce_rate],
  filters: [device_type: "mobile"],
  limit: 10
)

Summary

Functions

Returns a dimension breakdown for workspace_id over the window.

The supported breakdown dimensions, in declaration order.

The supported metrics, in declaration order.

Functions

breakdown(workspace_id, dimension, opts)

@spec breakdown(Ecto.UUID.t(), atom(), keyword()) :: [map()]

Returns a dimension breakdown for workspace_id over the window.

Options

  • :window%{start_at: from, end_at: to} (required), an inclusive-start/exclusive-end DateTime range matched on inserted_at.
  • :metrics — subset of metrics/0 (default: all). Mixing event/person metrics with session metrics composes a session sub-aggregate.
  • :filters — keyword of dimension equality filters for drilldown, e.g. [device_type: "mobile"]. Keys must be supported dimensions.
  • :limit — cap on returned rows.
  • :order_by{metric, :asc | :desc} (default: the first requested metric, descending).

Unknown dimension or metric raises ArgumentError. An empty window yields []. Null dimension values bucket as (not set).

dimensions()

@spec dimensions() :: [atom()]

The supported breakdown dimensions, in declaration order.

metrics()

@spec metrics() :: [atom()]

The supported metrics, in declaration order.