atrixANALYTICS
SQL

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 desc

Tables

TableWhat it holds
eventsEvery event, with hot properties materialised as m_* columns (m_url, m_os, m_country, …)
personsPeople and their properties
person_distinct_idsWhich distinct ids belong to which person
groupsGroup profiles (companies, teams)
sessionsOne row per session: start, end, duration, entry and exit, counts
cohort_peopleMaterialised cohort memberships
revenue_eventsNormalised 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 writeMeans
properties.planThe event property plan
properties['utm']['source']A nested key (up to 8 levels)
person.properties.planThe person property plan (only in a query over one events table)
e.properties.planThe 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:

  1. The compiler rewrites every table reference into a subquery with your project and environment forced in, and a verifier re-checks the compiled output.
  2. ClickHouse row policies on the database user that runs customer SQL.
  3. A sampled audit of the query log.

Limits

PlanTimeoutRows readRows returned
Free10 s200 million10,000
Starter20 s500 million50,000
Growth30 s1 billion100,000
Scale, Enterprise30 s2 billion100,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.

On this page