Four hops, no magic
Analytics platforms are usually described in terms of what they promise rather than what they do. Here is the actual path an event takes, in order, with the guarantee at each step spelled out.
Follow one event from a click in a browser to a number on a dashboard.
Analytics platforms are usually described in terms of what they promise rather than what they do. Here is the actual path an event takes, in order, with the guarantee at each step spelled out.
Each step is independently observable, so when a number looks wrong you can find out where it went wrong.
The browser SDK reads the page URL, language, device form factor and OS family, and attaches a first-party anonymous_id and session_id. Your own custom_dimensions and custom_metrics ride along on the same event.
Events are queued and sent as a JSON array rather than one request per interaction. The collector accepts up to 1000 events per request, which is also what makes a nightly server-side job cheap.
The batch arrives as POST /il/analytics/{tenant_id}/{site_id}/events. That pair in the URL is the credential: it is matched against your registered ClickHouse configuration, and a pair with no match is rejected with 403 rather than written anywhere.
Because tenant_id and site_id are read from the path and never from the body, a client cannot write into somebody else's stream by editing its payload. The collector then resolves country_code from the request IP by GeoIP and discards the IP.
Events are written to website_events in your ClickHouse, partitioned by month with toYYYYMM(event_date) and sorted by (user_id, event_time, event_type, event_id) — so a per-user timeline is a range read rather than a scan.
Columns carry ZSTD codecs, event_time uses Delta, and the low-cardinality dimensions are declared as such. A 24-month TTL with ttl_only_drop_parts means expiry drops whole parts instead of rewriting data.
Opening a report sends its definition to POST /il/analytics/{tenant_id}/{site_id}/report-query. The builder turns metrics, dimensions, filters and a time range into one aggregate GROUP BY — and only against a whitelist of allowed columns, so a report definition can never become arbitrary SQL.
Because ClickHouse is columnar, counting unique visitors across a large table reads only the columns involved. And since the database is yours, any question the console cannot express is a SQL client away.
Ingest needs no token. Reading reports does. That asymmetry is deliberate.
# The tenant_id + site_id pair in the path is the ingest credential.
# There is no Authorization header on this endpoint.
curl -sS -X POST \
'https://api.infralytiqs.com/il/analytics/acme/acme-www/events' \
-H 'Content-Type: application/json' \
-d '[
{
"event_type": "page_view",
"page_url": "https://acme.com/pricing",
"anonymous_id": "a7f3c1e0-9b2d-4c8a-8f11-2d6b5e4c9a13",
"session_id": "s-2026-07-25-0914",
"language_iso_code": "en-GB",
"device_type": "desktop",
"device_os": "macOS",
"custom_dimensions": { "plan": "trial", "release": "2026.07.3" },
"custom_metrics": { "scroll_depth": 82 }
},
{
"event_type": "cta_click",
"event_subtype": "pricing_start_trial",
"page_url": "https://acme.com/pricing",
"anonymous_id": "a7f3c1e0-9b2d-4c8a-8f11-2d6b5e4c9a13",
"session_id": "s-2026-07-25-0914",
"user_id": "usr_10482"
}
]'
# 201 Created
# { "success": true, "message": "2 event(s) ingested successfully", "count": 2 }# An unknown tenant/site pair is refused outright — nothing is stored.
# 403 Forbidden
# { "error": "Invalid tenant_id or site_id. No matching ClickHouse configuration found." }
# An empty array is a client error rather than a silent success.
# 400 Bad Request
# { "error": "At least one event is required" }
# Batches are capped, so split anything larger client-side.
# 400 Bad Request
# { "error": "Maximum 1000 events per batch" }
# Use the reserved __all_sites__ segment for a tenant-wide configuration
# that is not scoped to one site:
curl -sS -X POST \
'https://api.infralytiqs.com/il/analytics/acme/__all_sites__/events' \
-H 'Content-Type: application/json' \
-d '{ "event_type": "nightly_rollup_complete" }'# Reading reports DOES require credentials. Exchange a tenant's
# client key and secret for a short-lived JWT.
curl -sS -X POST 'https://api.infralytiqs.com/il/token' \
-H 'companyId: 665f1c9e4a2b3d0012ab34cd' \
-H 'tenantName: acme' \
-H 'clientKey: 3f9a1c7d5e2b8064af31c9d2' \
-H 'clientSecret: 9d41e7c8b25a06f3ac18de74b09f52a6c3e81d47f265ba90c1d38e07f4b2a659'
# The response carries a JWT in data.token, signed with your clientSecret.
# Its tokenId claim is what you send as x-il-token on read requests.# Unique visitors per day for the last 30 days, by country.
curl -sS -X POST \
'https://api.infralytiqs.com/il/analytics/acme/acme-www/report-query' \
-H 'Content-Type: application/json' \
-H 'x-il-token: 1f4c8a92-6e30-4b57-9d21-c8a70f3b5e14' \
-d '{
"query": {
"metrics": [
{ "agg": "uniqExact", "field": "anonymous_id", "label": "Unique Visitors" },
{ "agg": "count", "label": "Events" }
],
"dimensions": [{ "field": "country_code" }],
"filters": [
{ "field": "event_type", "op": "eq", "value": "page_view" }
],
"timeRange": { "preset": "last_30_days", "granularity": "day" },
"orderBy": { "field": "Unique Visitors", "dir": "DESC" },
"limit": 20
},
"timezone": "Europe/London"
}'
# { "success": true, "data": [...], "columns": [...], "rowCount": 20, "totalCount": 187 }Sources on the left, your storage on the right.
Capture
Queued JSON array
Up to 1000Plain HTTPS POST
No native SDKBatched job
Server-sideValidate
Matched to config
403 if unknowncountry_code
IP discardedPersist
MergeTree
Monthly partitions24 months default
Yours to changeQuery
Compiled to SQL
Column whitelist14 panel types
x-il-tokenAny client
No gatekeeperEvery arrow is an HTTPS request or a database connection. There is nothing proprietary in between.
Facts about the pipeline rather than a benchmark of your traffic.
0
Events per ingest request
Hard cap; split larger batches client-side
0
Default retention
A TTL clause on your table — change it freely
0
Visualisation types
Line through to DAM storage quota bars
0
Events sampled away
Nothing in the pipeline samples
The getting-started guide covers SSO sign-in, creating a tenant, connecting your ClickHouse server and sending your first event.