Skip to content

Querying your data

Beyond chat and dashboards, you can query your events directly with SQL: use POST /api/v1/query/execute in the HTTP API, or ask the assistant to run something specific.

All of your analytics data is exposed as one queryable view named events, automatically scoped to your projects server-side. There is no other table, and no way to address anything outside your scope. The platform enforces that boundary.

SELECT event_name, COUNT(*) AS n
FROM events
WHERE __time > CURRENT_TIMESTAMP - INTERVAL '7' DAY
GROUP BY 1
ORDER BY 2 DESC
LIMIT 10

Useful columns: event_name, user_id, session_id, platform, project_id, properties (JSON), and __time (the event’s timestamp column, used by every time filter and bucket).

Queries are read-only (SELECT only), resource-capped, and cached briefly server-side; a cache_ttl field on the request controls the cache window.

  • Filter with __time and intervals: WHERE __time > CURRENT_TIMESTAMP - INTERVAL '30' DAY
  • Bucket with TIME_FLOOR: SELECT TIME_FLOOR(__time, 'P1D') AS bucket, COUNT(*) FROM events GROUP BY 1. Periods are ISO-8601 strings (PT1H hourly, P1D daily, P1W weekly).

Extract values with JSON_VALUE before filtering or grouping. Direct comparison against the properties column fails with a type error:

SELECT JSON_VALUE(properties, '$.plan') AS plan, COUNT(*) AS n
FROM events
WHERE event_name = 'signup_completed'
GROUP BY 1

The query engine’s SQL dialect has two rules that trip everyone once:

  1. GROUP BY and ORDER BY can’t reference SELECT aliases. Use the ordinal or repeat the expression:

    -- ✅ works
    SELECT TIME_FLOOR(__time, 'P1D') AS event_day, COUNT(*) AS n
    FROM events GROUP BY 1 ORDER BY 1
    -- ❌ "Column not found": GROUP BY event_day
  2. Some natural aliases are reserved words. day, hour, month, and friends fail confusingly as bare aliases. Write AS event_day (or quote the alias) instead of AS day.

Also: counting distinct users (COUNT(DISTINCT user_id)) is approximate at scale (the trade every high-volume analytics engine makes), so treat small differences between runs as noise.

For simple time series without writing SQL, GET /api/v1/query/metrics/{metric} returns bucketed counts (count, unique_users, unique_sessions) between two timestamps at minute/hour/day granularity. It’s what powers the console’s sparklines. See the HTTP API reference.

The artifacts the assistant builds are readable over the same API: list and fetch your dashboards (each fetch re-runs the widget queries against live data) and your reports (frozen snapshots with their query receipts). See the HTTP API reference for GET /api/v1/query/dashboards and GET /api/v1/query/reports. Creating them is the assistant’s job, so there’s no public write surface.