SQL
Query your events, people, sessions and revenue with SQL, safely scoped to your project.
Atrix SQL is ClickHouse SQL, restricted to SELECT and a vetted function list, over virtual tables that are
already scoped to your project and environment. Use it from Insights → SQL in the console, or from the
region API with a token that holds the named sql.raw scope.
select properties.plan as plan, count() as signups, uniqExact(person_id) as people
from events
where event = 'signed_up' and timestamp > now() - interval 30 day
group by plan
order by signups descTables
| Table | What it holds |
|---|---|
events | Every event, with hot properties materialised as m_* columns (m_url, m_os, m_country, …) |
persons | People and their properties |
person_distinct_ids | Which distinct ids belong to which person |
groups | Group profiles (companies, teams) |
sessions | One row per session: start, end, duration, entry and exit, counts |
cohort_people | Materialised cohort memberships |
revenue_events | Normalised revenue from connected providers, in minor units |
Deduplicated and deleted rows are already folded away, and erased users are excluded. The full column list and every allowed function are on Tables and functions, generated from the compiler itself.
Property shortcuts
| You write | Means |
|---|---|
properties.plan | The event property plan |
properties['utm']['source'] | A nested key (up to 8 levels) |
person.properties.plan | The person property plan (only in a query over one events table) |
e.properties.plan | The same, through a table alias |
String values come back unquoted; other values come back as JSON text, so cast them: toFloat64OrNull(properties.amount).
What is not allowed
Only SELECT, WITH and UNION / INTERSECT / EXCEPT. Not allowed: SETTINGS, FORMAT,
INTO OUTFILE, table functions, ARRAY JOIN, SAMPLE, placeholders, database-qualified names, and functions
that read outside your rows or describe the server (dictGet, joinGet, getSetting, currentUser,
version, sleep, throwIf, and the in / notIn function forms). A CTE may not reuse a table name.
Errors say exactly which rule was hit: parse_error, too_long, not_a_select, forbidden_clause,
forbidden_function, forbidden_expression, unknown_table, qualified_name, invalid_identifier,
invalid_limit, cte_shadows_table.
Tenant isolation
Your SQL is compiled, not passed through. Three independent layers keep it inside your project:
- The compiler rewrites every table reference into a subquery with your project and environment forced in, and a verifier re-checks the compiled output.
- ClickHouse row policies on the database user that runs customer SQL.
- A sampled audit of the query log.
Limits
| Plan | Timeout | Rows read | Rows returned |
|---|---|---|---|
| Free | 10 s | 200 million | 10,000 |
| Starter | 20 s | 500 million | 50,000 |
| Growth | 30 s | 1 billion | 100,000 |
| Scale, Enterprise | 30 s | 2 billion | 100,000 |
LIMIT defaults to 1,000 and is capped by the plan; OFFSET at most 1,000,000; query text at most 100 KB.
A project runs at most two queries at once. Hitting a resource limit answers 422 query_too_large.
From the API
curl -X POST https://eu.api.analytics.atrix.dev/sql \
-H "Authorization: Bearer $REGION_TOKEN" \
-H 'Content-Type: application/json' \
-d '{ "sql": "select event, count() from events group by event order by 2 desc", "limit": 20 }'The region token must carry sql.raw; see Region API. Add "include_sql": true to see
the compiled SQL that actually ran.