Skip to main content
The Analytics app stores your project’s data in ClickHouse and gives you two ways to explore it:
  • Tables - a point-and-click grid for browsing raw rows. Best for “what just happened?” triage.
  • Queries - a read-only ClickHouse SQL workspace for aggregation, joins, and reusable analysis.
Both read from the same dataset and are automatically scoped to the current project and branch, so you never see another tenant’s data and you never have to filter by project_id yourself.
This guide covers how to use Tables and Queries. For enabling the app and capturing events from the SDK, see the Analytics overview.

What you can query

Your dataset is exposed as a set of read-only views. Reference them directly by name (e.g. events) or fully-qualified (default.events) - both work.
Run SHOW TABLES or DESCRIBE events in the Queries workspace to discover columns at any time - both are allowed.

The events table

events is the table you’ll use most. Its columns are:
team_id on events is reserved and currently always NULL. Don’t build team-level analytics on it - join to team_member_profiles via user_id instead.

Event types and their payloads

The shape of data depends on event_type. The built-in event types are:

Tables

Open Analytics → Tables, then pick a table from the sidebar (it opens on events by default). The grid shows every column the table returns, newest rows first. What you can do here:
  • Search - type in the filter to match text across all columns at once.
  • Sort - click any column header. Each table has a sensible default (e.g. events sorts by event_at descending).
  • Toggle timestamps - switch any date/time column between relative (“3 minutes ago”) and absolute display from the Columns menu.
  • Show/hide columns - trim the grid to what you care about.
  • Inspect a row - click a row to open a detail dialog with every column and a pretty-printed view of the JSON data payload.
  • Export - download the current result set as CSV.
Rows load incrementally as you scroll (50 at a time), so large tables stay responsive. Use Tables for fast incident triage; switch to Queries when you need to aggregate or correlate across rows.

Queries

Open Analytics → Queries to get a SQL editor. Write a query, run it, and the results appear in the same grid (with the same sorting, search, and CSV export as Tables). A minimal starting point:

Automatic project scoping

Every query runs against your current project and branch only. Row-level security injects the tenant filter for you, so this:
returns only your events - no WHERE project_id = ... required. Adding explicit tenant filters is harmless but unnecessary, and you cannot override the scoping to read other tenants’ data.

What’s allowed

The workspace is strictly read-only. You can run:
  • SELECT and WITH (CTEs)
  • SHOW TABLES, SHOW GRANTS, DESCRIBE, EXPLAIN
Anything that writes or reaches outside the dataset is blocked, including INSERT, UPDATE, DELETE, ALTER, CREATE, DROP, TRUNCATE, multi-statement scripts, and table functions like file(), url(), remote(), and s3(). Most system.* tables are off-limits too (table/column metadata is the exception).

Limits

Queries run inside a budget so a single query can’t overload the dataset: If you hit the row or byte cap the query fails rather than returning a partial result, so always scope with WHERE, aggregate, or add a LIMIT. If a query times out, narrow the time range (event_at >= now() - INTERVAL 1 DAY) or pre-aggregate.

Parameterized queries

Use ClickHouse’s {name:Type} placeholders to keep values out of your SQL string and avoid escaping issues:

Working with the data payload

data is a real ClickHouse JSON column, so you can reach into it with dot notation and cast as needed:
For values you want to treat as a specific type, cast explicitly:
To discover which keys exist in a payload, expand them:

Saving queries

Save a query to reuse it later: queries live in folders in the sidebar. You can Save a new query, Save As to copy one, or overwrite the selected query after editing it. Selecting a saved query loads its SQL and runs it immediately. Deleting a folder removes the queries inside it.

Examples

Daily active users (last 7 days)

Top pages by views (last 24 hours)

Event volume per hour

Most-clicked elements

Recent sign-up rule rejections

New users this week

Token refreshes by country

Tips & gotchas

  • Events are eventually consistent. New events are ingested asynchronously and can take a few seconds to appear. If a fresh event is missing, wait and re-run.
  • Always bound your time range. Filtering on event_at keeps queries fast and well under the result limits.
  • Query the views, not internals. Stick to the table names listed above (the default.* views). Internal physical tables aren’t granted to the query runner and bypass the tenant safety policies.
  • Metadata columns are strings. On users, fields like client_metadata and server_metadata are stored as JSON-encoded String, so parse them with JSONExtract* functions rather than dot notation.
  • Legacy rows may use camelCase keys. Older $sign-up-rule-trigger rows can carry ruleId instead of rule_id; use COALESCE over both if you query far back in history.