Owlmetry
MCP

Stats

Query daily and hourly time-series rollups for trend analysis via MCP.

Time-Series Rollups are pre-aggregated daily and hourly count tables for the four event-shaped data sources — events / metric_events / funnel_events / questionnaire_responses. They power the subtle sparkline charts on dashboard cards and arbitrary date-range trend queries that survive raw-event retention pruning.

Kinds: events, users, sessions, metric_completions, funnel_completions, questionnaire_responses. Grains: daily, hourly. Buckets are UTC; the in-progress bucket is excluded by default so a partial day or hour can't render as a misleading dip. Reads always hit the project-rollup row (one row per (project, is_dev, bucket)) unless a single-app filter is supplied — never a SUM across apps at query time.

Two background jobs maintain the tables — stats_aggregate_hourly at :05 UTC and stats_aggregate_daily at 00:30 UTC, each re-aggregating the trailing 3 buckets to absorb late-arriving events from offline SDKs. Historical backfills (e.g. first-time rollout or repair after a gap) are an operator action — run pnpm backfill in the monorepo against the production DB. It re-aggregates the trailing 365 days using DELETE+INSERT … SELECT … GROUP BY in a single transaction per bucket range, so re-running over the same window is idempotent and stale rows never survive. unique_users and unique_sessions are per-bucket distincts and non-additive across buckets — sparkline value lines plot the additive count columns.

query-stats-bucketed

Returns one zero-padded point per bucket in the requested window. Use it to power sparklines, trend dashboards, or year-over-year comparisons — every kind of dashboard card on /dashboard is backed by this endpoint.

ParameterTypeRequiredDescription
kindenumYesevents / users / sessions / metric_completions / funnel_completions / questionnaire_responses
grainenumYesdaily or hourly
project_idUUIDOne ofProject ID. Mutually exclusive with team_id
team_idUUIDOne ofTeam ID — aggregates across every accessible project in the team
app_idUUIDNoNarrow to one app within the chosen scope
daysnumberNoTrailing UTC days for grain=daily (1–365, default 30). Ignored when from/to are set
hoursnumberNoTrailing UTC hours for grain=hourly (1–2160, default 24). Ignored when from/to are set
fromstringNoExplicit start (YYYY-MM-DD for daily, ISO 8601 for hourly). Pair with to
tostringNoExplicit end (inclusive at the bucket level)
excluding_currentbooleanNoDrop the in-progress bucket. Defaults to true; set false to include it
data_modeenumNoproduction / development / all. Defaults to production
slugstringNoNarrow metric_completions / funnel_completions to one definition

Response shape (StatsBucketedResponse):

{
  "kind": "events",
  "grain": "daily",
  "from": "2026-04-20",
  "to": "2026-05-19",
  "data": [
    { "bucket": "2026-04-20", "value": 1240 },
    { "bucket": "2026-04-21", "value": 1310 },
    ...
  ]
}

events, users, and sessions all read the same events_{daily,hourly} rollup; the kind selects which column maps to value (event_count / unique_users / unique_sessions). metric_completions filters to phase='complete'. funnel_completions filters to each funnel's terminal step (resolved from funnel_definitions). questionnaire_responses returns submitted_count.

Backfill an older range

Backfilling the rollup tables is an operator action and is not exposed via MCP or REST. Run pnpm backfill in the monorepo on the production VPS — it re-aggregates the trailing 365 days against the database directly. Idempotent across re-runs. Aggregation tables are explicitly excluded from retention pruning, so historical buckets stay queryable indefinitely.

Ready to get started?

Connect your agent via MCP or CLI and start tracking.