Documentation
¶
Overview ¶
Package web composes the one-glance web-analytics view — live visitors, top pages, referrers, UTM sources, device split — from $pageview events. This is the Plausible-shaped report indie devs otherwise run a SECOND tool for; here it's the same engine, same events, one binary. Deterministic like every other report.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Recorded ¶ added in v0.29.0
type Recorded struct {
TopPages int `json:"top_pages"`
Referrers int `json:"referrers"`
UTMSources int `json:"utm_sources"`
DeviceSplit int `json:"device_split"`
Browsers int `json:"browsers"`
OSes int `json:"oses"`
Countries int `json:"countries"`
UTMMediums int `json:"utm_mediums"`
UTMCampaigns int `json:"utm_campaigns"`
EntryPages int `json:"entry_pages"`
ExitPages int `json:"exit_pages"`
TopTitles int `json:"top_titles"`
AIReferrers int `json:"ai_referrers"`
}
Recorded is the untruncated total behind each ranked dimension: how many pageviews (for per-pageview dimensions) or first-touch visitors (for the per-visitor ones) actually carried a value, before rank() cut the list down to what fits on screen.
type Result ¶
type Result struct {
PeriodDays int `json:"period_days"`
Visitors int `json:"visitors"` // unique visitors in period
Pageviews int `json:"pageviews"` // total $pageview in period
LiveNow int `json:"live_now"` // unique visitors in the last 5 minutes
TopPages []Row `json:"top_pages"`
Referrers []Row `json:"referrers"` // grouped by host, "" → "direct"
UTMSources []Row `json:"utm_sources"` // only when utm_source is present
DeviceSplit []Row `json:"device_split"` // mobile / desktop
// the dimensions people open first — browsers/os come from the ingest-time UA
// parse, countries from ingest-time geo (when enabled), entry pages from the
// SDK's session_id, titles from the SDK's title prop
Browsers []Row `json:"browsers"`
OSes []Row `json:"oses"`
Countries []Row `json:"countries"`
UTMMediums []Row `json:"utm_mediums"`
UTMCampaigns []Row `json:"utm_campaigns"`
EntryPages []Row `json:"entry_pages"`
ExitPages []Row `json:"exit_pages"` // last pageview of each session — where visits END
TopTitles []Row `json:"top_titles"`
Hours [24]int `json:"hours"` // pageviews by UTC hour of day — the activity rhythm
// engagement — from $engagement events (SDK measures visible+focused time).
// Omitted (zero) when the SDK predates engagement tracking.
HasEngagement bool `json:"has_engagement"`
AvgEngagedSecs int `json:"avg_engaged_secs"` // mean engaged time per engaged visitor
BounceRatePct int `json:"bounce_rate_pct"` // 1 pageview AND <10s engaged
// the AI channel — humans arriving FROM AI assistants (chatgpt/claude/perplexity...).
// distinct from AI crawlers, which the bot filter drops before storage.
AIVisitors int `json:"ai_visitors"`
AIReferrers []Row `json:"ai_referrers"`
// Every ranked list above is TRUNCATED to its top N. A reader that sums the rows it can
// see and calls that the total gets a denominator that only covers the visible head: a
// site with 40 countries, 20 US visitors out of 100, rendered "US 20 · 52%" because the
// ten visible rows summed to 38. The visible shares then also add to exactly 100%,
// asserting there is no tail at all. These are the pre-truncation recorded totals — the
// only honest denominator for "share of recorded" — so no surface has to re-derive one
// from rows it was already handed in truncated form.
Recorded Recorded `json:"recorded"`
}
Result is the web overview for a period.
func ComputeRange ¶ added in v0.29.0
ComputeRange is ComputeWindow over an EXPLICIT [from, to) — the form the dashboard needs.
ComputeWindow derives its bounds from a duration and an as-of, which produces a ROLLING window: "last 10 days" means now−240h. The trends path next to it aligns the same preset to calendar days (day0−9d .. now) precisely so the tile, /v1/trends and the MCP tool agree. Two tiles sat side by side on the same row, both labelled "· 10d", measuring windows that differ by up to a day at each edge — and on a young instance that is the difference between a prior window with data in it and one without, so one tile showed "71x vs prior" and the one beside it showed no delta at all. Taking the bounds as arguments is what makes ONE window definition possible for the whole row.
func ComputeWindow ¶ added in v0.15.0
ComputeWindow is Compute over an arbitrary window rather than a whole number of days, so the dashboard's sub-day presets (6h, 12h) can report the SAME window in the tiles as the chart. Without it a 6h range moved the chart only and left every tile on 24h, which is a range control that lies about what it changed.