◔ Analytics & measurement

Server logs or JavaScript analytics: two measurements compared

Why server logs and JavaScript analytics report different numbers, what each method actually sees and how to combine them for a credible picture of traffic.

It happens all the time: the analytics dashboard shows a thousand visits in a day, while processing the server logs gives five thousand. Neither number is "wrong". They measure different things at different points along the path of a request, and understanding that difference is the first step towards trusting your data.

Two vantage points

When a browser opens a page, three things happen in order:

  1. the browser sends an HTTP request to the server;
  2. the server responds with the HTML and almost always writes a line to its access log;
  3. the browser parses the page, downloads resources and runs scripts, including the analytics one, which sends a signal (a "hit") to a collection service.

Logs observe step 2, JavaScript analytics observe step 3. Everything that happens between the two, or never reaches step 3, creates the gap.

What logs see

A typical access log line in combined format contains the IP, the date, the requested method and path, the status code, the response size, the referrer and the user agent:

203.0.113.7 - - [12/Mar/2025:10:15:32 +0100] "GET /backup-guide/ HTTP/2.0" 200 18234 "-" "Mozilla/5.0 ..."

From this data you can derive:

  • every request, including bots, crawlers, monitoring tools and clients without JavaScript;
  • errors: 404 pages, chains of 301 redirects, 500 errors the user sees but the analytics script never records because the page does not load;
  • non-HTML resources: PDF downloads, images, RSS feeds, API calls.

The limitation is that logs know nothing about what happens after loading: how far the user scrolls, whether they click a button that does not trigger a new request, whether they stay on the page for one second or ten minutes.

What the JavaScript snippet sees

The client-side script records only visits from browsers that run JavaScript and do not block the collection service. In return it sees what logs ignore:

  • interactions without a reload, such as opening menus, playing a video or submitting forms handled by JavaScript;
  • screen size and device characteristics;
  • navigation inside single page applications, where the server sees only the initial request;
  • time on page and scroll depth, if configured.

Why the numbers do not match

Cause Effect on logs Effect on JS analytics
Bots and crawlers Counted Almost always excluded
Ad blockers and privacy filters Counted Lost
Pages served from browser cache or a CDN Often not recorded at the origin Counted
User closes the page before the script runs Counted Lost
Internal navigation in a SPA A single request Several page views

The CDN case deserves attention: if the site is served through a content delivery network, requests that find the page in cache never reach your server, and the useful logs are the CDN's, not the origin's.

How to use them together

The healthiest approach is to give each source the questions it handles best.

Ask the logs: - which URLs return errors and how often; - which crawlers visit the site and how frequently, useful for technical SEO; - how many times non-HTML files are downloaded; - whether there are unusual spikes that suggest abuse or scanning.

Ask JavaScript analytics: - how people behave on the page; - which paths lead to a conversion; - which campaigns bring visits that genuinely engage.

In my work I find a periodic check useful: I pick a page with steady traffic and compare the human page views estimated from the logs, after filtering known bots and resource requests, with those recorded by the script. If the ratio stays stable over time, the analytics are consistent. If it changes suddenly, something has broken: a script removed by mistake, a consent setting that blocks collection, a new bot pretending to be a browser.

Filtering logs sensibly

To bring logs closer to an estimate of human visits:

  • exclude requests for images, stylesheets, scripts and fonts;
  • exclude user agents that declare themselves bots, crawlers or spiders;
  • exclude status codes other than 200 when counting page views;
  • group closely spaced requests from the same IP and user agent.

The result will still be an estimate, but one independent of ad blockers, and therefore a good point of comparison.

In short

  • Server logs and JavaScript analytics observe two different moments of the same visit.
  • Logs see every request, bots and errors included, but not interactions after loading.
  • The script sees on-page behaviour but misses anyone who blocks JavaScript or the collection service.
  • Periodically comparing the two sources on stable pages helps uncover tracking problems.
MM
Marco Marzaduri

Marco Marzaduri works in cybersecurity, digital forensics and web development. A computer science graduate, he combines rigorous technical analysis with attention to the people who use technology.

Read also