Why no two analytics tools agree on your traffic
Google Analytics says one thing, Search Console another, your server logs a third. None of them is broken. They count different things, and once you know which, the gaps stop being worrying.
9 min read
In this article
- 1Start with what each tool can see
- 2Bots, crawlers and other things that aren't people
- 3Ad blockers and privacy browsers
- 4The cookie banner
- 5What counts as one visitor
- 6Sessions, bounces and other words that don't travel
- 7Time zones, and the day that isn't over yet
- 8Single-page apps
- 9A ten-minute check for your own site
- 10Which number to use for what
Put two analytics tools on the same website for a week and they will disagree. Not by a rounding error, either. One reporting half of what the other does is normal, and your server logs or Cloudflare dashboard can easily show more than both of them put together.
We build an analytics tool, so we hear the question a lot, usually as “which one is right?” The honest answer is that most of them are right about what they count. They just don't count the same thing, and the labels hide it. “Visitors”, “users” and “sessions” sound interchangeable. They almost never are.
Here's where the gaps come from, roughly in order of how much they tend to matter, and a quick way to check your own site.
Start with what each tool can see
Every number on an analytics dashboard is a filtered count of things that happened. The filter is the part that differs, and it differs a lot more than the dashboards let on.
| Source | What it counts | Compared with the rest |
|---|---|---|
| Server logs | Every request that reached your server: people, bots, crawlers, uptime checks, link previews | Highest |
| Cloudflare's dashboard | Unique IP addresses that requested your site, bots included | Very high |
| Search Console | Clicks on your site in Google's results, whether or not the page finished loading | Google only, but often more than your analytics shows for Google |
| A cookie-free script | Browsers that loaded a page and ran the script, minus the bots it filters out | In the middle |
| A script behind a cookie banner | The same, but only for people who clicked accept | Lowest |
Put those in order and you get something like the chart below. Each step down is one of the causes in the rest of this article.
How 5,000 requests become 1,400 visits
Illustration, not real data
Page requests in the server log
5,000
Bots, crawlers and uptime checks
−2,100
Requests from people
2,900
Script blocked by an ad blocker or browser
−450
Counted by a cookie-free script
2,450
Declined or ignored the cookie banner
−1,050
Counted by GA4 in basic consent mode
1,400
Bots, crawlers and other things that aren't people
A big share of the requests to any public website come from software: search engine crawlers, SEO tools, AI crawlers, uptime monitors, link previews in chat apps, and scripts trying /wp-login.php on sites that have never run WordPress. Server logs count all of it. So does Cloudflare's dashboard, which counts unique IP addresses and says plainly in its own documentation that its numbers will probably be higher than other analytics services.
Script-based tools skip most of this for free, because most bots never run JavaScript. The ones that do (headless browsers used for scraping, testing and some crawling) are what each tool's bot filter is for, and no two filters are the same. If one tool shows a burst of visits from a single country, all to the homepage, at four in the morning, with nobody staying longer than a second, that's usually a bot that got past it.
Ad blockers and privacy browsers
Content blockers like uBlock Origin ship with lists of tracking scripts, and Google Analytics is on every one of them. Brave blocks it out of the box. Plenty of privacy-focused tools end up on the same lists, so switching tools makes this smaller, not zero.
How much you lose depends almost entirely on who your visitors are. A site for developers loses far more to blockers than the site of a local bakery. No industry average will tell you yours. To measure it, compare a script-based count with something that can't be blocked, like your server log filtered down to real page requests from real browsers, for the same day.
The cookie banner
If your site runs Google Analytics behind a cookie banner, as most European sites do, then in basic consent mode everyone who clicks reject, or ignores the banner and leaves, is invisible to it. In advanced consent mode Google sends cookieless pings for those visitors instead and, if your site is big enough to qualify, fills part of the gap with modelled estimates. So some of the users in your report were never counted. They were inferred.
How many people accept depends heavily on how the banner is designed, which is why two similar sites can show completely different numbers in GA. A tool that sets no cookies doesn't depend on the banner at all, and that alone often explains most of the gap between it and GA.
What counts as one visitor
This is the one that trips people up most, because the word is the same everywhere and the method behind it isn't.
Google Analytics recognises a returning visitor by an ID stored in a cookie. Clear your cookies, switch from phone to laptop or open a private window, and you're a new user. Safari also limits cookies set by scripts to seven days, so someone who reads your site every couple of weeks on an iPhone can arrive as a new user every single time.
Cookie-free tools do it differently. Plausible, for example, hashes the visitor's IP address and browser together with your domain and a secret salt, and deletes the salt every 24 hours. Lomen does something similar by default. The same person twice on Monday is one visitor. The same person on Monday and again on Thursday is two, because Thursday's key can't be linked back to Monday's.
Over one day, cookies and daily keys roughly agree. Over a month, they answer different questions.
A cookie-based tool counts a regular reader once for every browser it still recognises. A cookie-free one counts them once for every day they showed up. Neither is wrong, but you can't put the two monthly numbers side by side and expect them to match. (If you'd rather Lomen recognised people across days, you can opt in to a random ID in browser storage. It's off by default.)
Sessions, bounces and other words that don't travel
Even when two tools agree on visitors, the numbers below them rarely line up, because each tool defines them its own way.
GA4 ends a session after 30 minutes without activity. Its bounce rate also isn't the old “left after one page”. A session counts as engaged if it lasted longer than ten seconds, viewed at least two pages or triggered a key event, and bounce rate is the share of sessions that weren't engaged. A tool that calls every single-page visit a bounce will report a very different number for the same traffic. A blog where people read one long article and close the tab looks terrible in one tool and perfectly fine in the other.
So when you compare tools, compare pageviews and visitors, and leave bounce rate out of it.
Time zones, and the day that isn't over yet
Every tool has to decide when a day starts. GA uses the time zone set on your property. Search Console uses Pacific Time, always. From Stockholm, that means Search Console's Monday starts at nine in the morning, local time, for most of the year. A launch you post at breakfast on Tuesday lands on Tuesday in one tool and Monday in the other.
Same name, different day
Times on a Stockholm clock
Monday where you are (Stockholm)
Monday in Search Console (Pacific)
Post a launch at 07:00 on Tuesday and your analytics files it under Tuesday. Search Console files the same clicks under Monday.
The latest day is also unfinished in more than one way. Google says Search Console's data for today, and sometimes yesterday, is preliminary, and GA can take a day or two to process everything. Comparing yesterday across tools is the quickest way to talk yourself into a problem that doesn't exist. Compare last week instead.
Single-page apps
If your site is built with React, Next.js, Vue or similar and moves between pages without a full reload, every tool has to notice the address change on its own. Some do it automatically, some need a setting, and some leave it to you. Get it wrong one way and every visit looks like a single pageview. Get it wrong the other way, for example by keeping GA4's automatic tracking of history changes and also sending page_view events from your router, and every page counts twice.
A ten-minute check for your own site
You don't need to make the tools agree. You need to know whether the gap between them is stable.
- Pick a full day at least three days ago, so every tool has finished processing it.
- Write down pageviews and visitors from each tool for that day. Only those two.
- Divide one by the other. If GA shows 58% of what your cookie-free tool shows, 58% is your number.
- Do the same for a day a month earlier.
If the ratio is about the same both times, you're done. The tools disagree about the size of your audience but agree about its direction, and direction is what you make decisions on. If the ratio moved, something changed in between (a new banner, a deploy that dropped the script from some pages, a bot that found you), and that's worth finding.
Which number to use for what
| If you want to know | Use |
|---|---|
| Is my traffic growing? | One script-based tool, used consistently. Never mix two tools in one trend line. |
| How is Google search doing? | Search Console: clicks, impressions and the queries behind them. |
| How much load is my server under? | Server logs or your host's dashboard. Bots are load too. |
| How many people read this page? | A script-based tool that doesn't wait for a consent banner. Treat it as a floor, because of blockers. |
| Did that campaign work? | Whichever tool reads your UTM tags, compared with the week before. |
The one mistake worth avoiding is switching tools and comparing this month in the new one with last month in the old one. You'll see a jump or a drop that is entirely the tools' doing. If you switch, run both for two weeks, note the ratio, and start the new trend line on the day you switched.
For the record, this is what Lomen counts: pageviews from browsers that run its script, including page changes in single-page apps, with known bots and copies of your snippet on other sites filtered out, and visitors by a daily anonymous key, without cookies. It won't match your server logs either, for all the reasons above. But now you know why.