Skip to main content
View as Markdown

Analytics

Sovrium ships a built-in, first-party analytics engine. It tracks page views, sessions, referrers, UTM campaigns, and device breakdowns on a single unified event model — with no cookies, no fingerprinting, and no external services. All data stays on your server, which makes it GDPR-friendly by default.

Analytics is configured via the analytics property in the app schema. When enabled, Sovrium injects a lightweight (~1KB) tracking script that records page views via navigator.sendBeacon() to POST /api/analytics/collect.

Configuration

analytics accepts a boolean shorthand or an object for fine-grained control.

# Boolean shorthand — enable with all defaults
analytics: true

# Object form — override individual settings, keep defaults for the rest
analytics:
  enabled: true
  retentionDays: 365
  excludedPaths:
    - /admin/*
    - /api/*
  respectDoNotTrack: true
  sessionTimeout: 30
Property Default Range / Values Description
enabled true boolean Enable/disable analytics tracking.
retentionDays 365 1730 Days to retain analytics data. Older rows are automatically purged.
excludedPaths [] string[] (glob) URL patterns excluded from tracking (e.g. /admin/*, /api/*).
respectDoNotTrack true boolean Honor the browser DNT:1 header — those visitors are not tracked.
sessionTimeout 30 1120 (minutes) Idle period after which a new session begins.

Unified Events Model

All analytics events — page views, custom track calls, and future sources — share a single system.analytics_events table with an event_type discriminator column. This follows the industry-standard pattern used by PostHog, Mixpanel, and Amplitude, but self-hosted with no external dependency (see DEC-019).

system.analytics_events
  id              UUID PRIMARY KEY DEFAULT gen_random_uuid()
  app_name        TEXT NOT NULL
  event_type      TEXT NOT NULL          -- 'page_view' | 'track' | extensible
  event_name      TEXT NOT NULL          -- path for page_view, custom name for track
  org_id          TEXT                   -- organization scope (nullable pre-auth)
  timestamp       TIMESTAMPTZ NOT NULL DEFAULT now()
  visitor_hash    TEXT NOT NULL          -- privacy-preserving visitor identifier
  session_hash    TEXT NOT NULL          -- privacy-preserving session identifier
  properties      JSONB NOT NULL DEFAULT '{}'
Event type event_name properties payload
page_view The page path path, referrer, utm_*, device_type, browser_*, os_*, screen_*, language, country.
track The custom event name Arbitrary key-value metadata from an automation action or the tracking API.

The promoted columns (event_type, event_name, org_id, visitor_hash, session_hash, timestamp) drive efficient WHERE/GROUP BY queries; everything else lives in JSONB. The same privacy primitives — server-side visitor/session hashing (SHA-256, no PII stored), DNT respect, and the retention horizon — apply uniformly to every event type, and every row is org-scoped for multi-tenant isolation.

Querying Analytics

Aggregated analytics are exposed through admin-gated read endpoints. Inspect raw events for debugging or custom dashboards.

Endpoint Returns
POST /api/analytics/collect Public ingest endpoint hit by the tracking script.
GET /api/analytics/overview Totals + bucketed daily time series.
GET /api/analytics/pages Top pages by view count.
GET /api/analytics/referrers Referrer and UTM-campaign breakdown.
GET /api/analytics/devices Device-type and browser breakdown.
GET /api/analytics/campaigns UTM campaign analysis.
GET /api/analytics/events Admin-only raw event inspection (paginated, filterable).

Inspecting raw events

GET /api/analytics/events provides row-level visibility into the unified stream — complementing the aggregated endpoints. It is admin-only and supports filtering by event_type, event_name, and date range.

GET /api/analytics/events?event_type=track&limit=50&offset=0&from=2026-01-01&to=2026-04-15
Parameter Description
event_type Filter by type (page_view, track, …).
event_name Exact-match event name.
from / to ISO 8601 date range (inclusive).
limit Max results (default 50, max 1000).
offset Pagination offset (default 0).

Privacy & Compliance

  • No cookies, no fingerprinting. Visitors are identified by a server-computed SHA-256 hash; no client-side identifier is stored.
  • DNT respected by default. Visitors sending DNT:1 are not tracked when respectDoNotTrack is on.
  • All data is local. No third-party services and no external calls — analytics never leaves your server.
  • Bounded retention. Data older than retentionDays is automatically purged, aligning with the platform's data-minimisation posture (see Ecoconception).