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.

The pipeline, step by step

Each step is independently observable, so when a number looks wrong you can find out where it went wrong.

  1. The SDK captures and queues

    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.

    In your application
  2. The collector validates and enriches

    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.

    Infralytiqs
  3. ClickHouse stores the rows

    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.

    Your infrastructure
  4. The query API compiles SQL

    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.

    Infralytiqs · sub-second

The whole contract, in four requests

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 }

The same picture, as a diagram

Sources on the left, your storage on the right.

Capture

Browser

Queued JSON array

Up to 1000

Mobile

Plain HTTPS POST

No native SDK

Backend

Batched job

Server-side

Validate

Tenant + site

Matched to config

403 if unknown

GeoIP

country_code

IP discarded

Persist

website_events

MergeTree

Monthly partitions

TTL

24 months default

Yours to change

Query

Report DSL

Compiled to SQL

Column whitelist

Console

14 panel types

x-il-token

Your SQL

Any client

No gatekeeper

Every arrow is an HTTPS request or a database connection. There is nothing proprietary in between.

The numbers that shape the design

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

Questions about the mechanics

The tenant and site pair in the URL is the credential, and it is matched against your registered ClickHouse configuration before anything is written — an unknown pair gets a 403. It is a write-only, append-only path: it cannot read your data, enumerate your configuration or reach another tenant. Treat it the way you would treat any publishable analytics key, and keep the client key and secret, which do grant read access, in server-side configuration.
No. Both are read from the request path and injected server-side. Any tenant_id or site_id present in the JSON body is ignored, so editing the payload cannot redirect an event.
Yes. event_time is a field you can set, so a backfill is simply a batch of events with past timestamps. It defaults to now64(3) when you leave it out. Remember the 24-month TTL is evaluated on event_date, so very old events may be dropped unless you extend it first.
The collector resolves country from the request IP using GeoIP and then discards the IP, so you get the dimension without holding the identifier. Precise browser coordinates are supported but strictly opt-in per domain, and 0,0 is treated as absent.
Put it in custom_dimensions, or a number in custom_metrics. These are ClickHouse Map columns, so no migration is involved, and the report builder discovers the new keys from your own data and offers them alongside the standard fields.
No. The query builder compiles definitions against a fixed whitelist of columns and a fixed set of aggregation functions. Anything outside that is rejected rather than interpolated.

Set it up yourself

The getting-started guide covers SSO sign-in, creating a tenant, connecting your ClickHouse server and sending your first event.