architecture

Server-side versus client-side analytics: what each can actually see

The debate is usually framed as accuracy versus detail. That is roughly right, but the specific list of what each side can and cannot observe is more useful than the slogan.

The two approaches are usually described as a trade between accuracy and richness. That is a fair summary, but it hides the part that decides real configurations: the specific list of things each one physically can and cannot observe.

Client-side: measuring from inside the page

A script runs in the browser after the page loads and reports what it sees.

Only it can see:

  • engagement time — how long the tab was actually visible and active, as opposed to open
  • scroll depth
  • rage clicks, dead clicks, form abandonment
  • Core Web Vitals from real visitors — LCP, CLS, INP measured in the browser that experienced them
  • viewport, colour scheme, precise device capabilities
  • client-side route changes in single-page apps
  • anything a user did that produced no server request

It cannot see:

  • visits where the script was blocked, failed, or never ran
  • crawlers of any kind
  • requests to cached pages that never reach your application
  • anything at all before the page has loaded enough to execute scripts

Server-side: measuring the request

The count happens when the HTML is requested, in your application, at your origin, or at an edge worker in front of it.

Only it can see:

  • every request, including ones where scripts never ran
  • crawlers, including which AI crawlers read which pages
  • the true response status — a 404 or a 500 is a fact the page-side script on a broken page cannot report
  • time to first byte from the serving side
  • network-level bot signals, at the edge

It cannot see:

  • how long anybody looked at anything
  • whether the page rendered correctly, or at all
  • interaction of any kind
  • client-side navigation in an SPA, which produces no request
  • the difference between a page that loaded and a page that started to load

That last group is the reason server-side-only analytics feels thin in practice. You know a request happened. You know almost nothing about whether it was any good.

The comparison that actually matters

Client-sideServer-side
Blocked visitorsMissingCounted
CrawlersInvisibleVisible
Engagement timeYesNo
Scroll, rage clicksYesNo
Core Web VitalsYesNo
SPA navigationYesOnly with help
Bot filtering qualityWeakStrong at the edge
Cached pagesCountedMissed unless configured
Setup costOne tagInfrastructure work

Neither column is a subset of the other, which is why "which is better" has no answer and "which are you running" does.

The honest conclusion: run both

The configuration that answers the most questions is both collectors feeding one system, with a shared identifier so a single pageview seen twice is counted once.

That gives you: complete pageview counts, crawler visibility, real bot filtering, and engagement, vitals and interaction data. It also gives you something neither side alone can produce — the difference between the two counts, which is the share of traffic your script alone was missing.

The reason this configuration is rare has nothing to do with it being a bad idea. It is that server-side counting requires code in your own request path, which a hosted analytics vendor cannot put there on your behalf. The architecture is the constraint, not the product roadmap.

Getting deduplication right

If you run both, the one thing that must work is recognising one pageview seen by two collectors as one event.

That requires both sides to derive the same visitor identifier from the same inputs by the same method, and to agree on what a page path is — trailing slashes, query strings, case. Get it wrong in one direction and every number doubles. Get it wrong in the other and the edge count is discarded, which quietly returns you to client-side-only measurement while displaying a badge claiming otherwise.

It is the least glamorous part of the design and the part most worth checking before trusting any number that comes out of it.

Common questions

Is server-side analytics more accurate than client-side?

More complete for counting, less capable for describing. Server-side sees every request including blocked visitors and crawlers, but cannot observe engagement time, scroll depth, interactions or Core Web Vitals, because those happen in a browser it never touches. Whether that counts as more accurate depends entirely on which question you are asking.

Can server-side analytics track single-page app navigation?

Not on its own. A client-side route change produces no request to your server, so there is nothing to count. Either the app explicitly reports navigation to the server, or a client-side script handles it — which in practice means running both collectors, with the script covering in-page navigation and the server covering the initial load.

If I run both, will my pageviews be counted twice?

Only if deduplication is not implemented properly, and then every number doubles. Both collectors have to derive the same visitor identifier from the same inputs using the same method, and normalise paths identically. This is the part of a dual-collector setup most worth verifying before you trust any figure it produces.