Back to Blog
Architecture10 min read2026-07-07

Why ClickHouse Powers Server-Side Analytics Without a Client SDK

Client-side analytics SDKs are slow, blocked, and inaccurate. Server-side capture into a columnar store like ClickHouse fixes all three. Here's the architecture and why ClickHouse is the right engine for it.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

The problem with client-side analytics

The default way to add analytics is to drop a JavaScript SDK into your frontend. It works, but it has three structural problems that have gotten worse over time:

  1. 1It's blocked. Ad blockers and privacy extensions block most analytics scripts. Studies and ad-blocker usage data put the blocked share in the double digits — meaning you're missing a large, non-random slice of your users.
  2. 2It's slow. Every SDK is more JavaScript to download, parse, and execute on the client. It competes with your actual app for the main thread and hurts Core Web Vitals.
  3. 3It's inaccurate. Client clocks are wrong, events get dropped on navigation, bots and pre-renderers fire events, and you can't trust user-supplied data.

The alternative is server-side analytics: capture events at the infrastructure layer, where every request already passes, and you don't ship a single byte of tracking JS to the browser.

Server-side capture without an SDK

If every request flows through your ingress/proxy, the ingress already *sees* everything you'd want to track: the path, method, status, response time, referrer, user agent, country (from the edge), and timestamp. There's no need to ask the browser to report what the server already knows.

The architecture:

Request -> Ingress / proxy (Kong)
               |  emits an event per request (path, status, latency, geo, UA...)
               v
        Event pipeline
               |
               v
        ClickHouse (columnar event log)
               |
               v
        Dashboards / queries

No client SDK, nothing to block, zero added page weight, and the data is as trustworthy as your own infrastructure. This is exactly how PandaStack does server-side metrics and analytics: capture happens at the Kong ingress and a proxy layer, events land in ClickHouse, and there is no client SDK — your users never download a tracking script, and your analytics aren't lost to ad blockers.

The distinction worth drawing: metrics (performance — latency, error rates, throughput) and analytics (audience — page views, referrers, geography) come from the same request stream but answer different questions. Both fall out naturally from server-side capture.

Why ClickHouse specifically

You could dump events into Postgres, but analytics workloads have a very particular shape that columnar databases are built for. ClickHouse is an open-source column-oriented OLAP database, and it fits this job almost perfectly.

Columnar storage

Analytics queries touch *few columns across many rows* — "count requests by country for the last 7 days" reads two columns out of twenty, across billions of rows. A row store reads every column of every row; a column store reads only the columns you ask for. That alone is an order-of-magnitude I/O reduction.

Compression

Columns of similar data compress extremely well. A column of country codes or status codes has low cardinality and compresses to a fraction of its size. ClickHouse routinely achieves high compression ratios, which means less disk, less I/O, and faster scans.

Append-optimized, query-fast

An event log is append-only and read-heavy — exactly ClickHouse's MergeTree sweet spot. It ingests millions of rows per second per node and runs aggregations over huge ranges in milliseconds.

-- The kind of query that's instant on ClickHouse, painful on a row store
SELECT
    toStartOfHour(ts) AS hour,
    country,
    count() AS requests,
    quantile(0.95)(latency_ms) AS p95
FROM events
WHERE ts >= now() - INTERVAL 7 DAY
GROUP BY hour, country
ORDER BY hour;

A schema that fits

CREATE TABLE events (
    ts        DateTime,
    path      LowCardinality(String),
    status    UInt16,
    latency_ms UInt32,
    country   LowCardinality(String),
    ua_family LowCardinality(String)
) ENGINE = MergeTree
ORDER BY (ts, path)
TTL ts + INTERVAL 90 DAY;   -- auto-expire old raw events

LowCardinality dictionary-encodes repetitive string columns for big space and speed wins, and a TTL clause lets old raw data age out automatically while you keep rolled-up aggregates.

ClickHouse vs a row store for analytics

NeedRow store (e.g. Postgres)ClickHouse
Few columns, many rowsReads whole rowsReads only needed columns
Compression on logsModestVery high (columnar + LowCardinality)
Aggregations over billions of rowsSlowMilliseconds-to-seconds
Append-heavy ingestOKExcellent (MergeTree)
Per-row updates/transactionsExcellentNot its job

The last row is the honest caveat: ClickHouse is not a transactional database. It's bad at single-row updates and OLTP. You don't put your orders table in it — you put your event firehose in it, and keep your application state in Postgres/MySQL. Right tool, right job.

The privacy angle

Server-side, SDK-less analytics is also a better privacy posture. You're not loading third-party scripts, you control exactly what's captured, and you can avoid cookies and cross-site tracking entirely while still getting accurate aggregate traffic data. That's increasingly important as browsers and regulations tighten on client-side tracking.

The takeaway

Client analytics SDKs are blocked, slow, and inaccurate. Capturing events server-side — at the ingress that already sees every request — fixes all three, and a columnar OLAP engine like ClickHouse is the natural store for the resulting high-volume, append-heavy, aggregation-driven event log. Keep transactional state in your relational database; point your analytics firehose at ClickHouse. That separation is why server-side analytics is both faster and more honest than the SDK status quo.

References

  • [ClickHouse — official documentation](https://clickhouse.com/docs)
  • [ClickHouse — MergeTree engine](https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree)
  • [ClickHouse — Why is it so fast?](https://clickhouse.com/docs/en/concepts/why-clickhouse-is-so-fast)
  • [web.dev — Core Web Vitals](https://web.dev/articles/vitals)

Want accurate analytics with zero tracking scripts? PandaStack captures metrics and analytics server-side into ClickHouse — no SDK required. Start free: [dashboard.pandastack.io](https://dashboard.pandastack.io)

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Architecture

Browse all Architecture articles →

See also