For a while I believed one of my side projects was growing at 25,761 percent. The dashboard said so, in a nice green arrow. The real number of human visitors from search that month was one.
If you run small sites and look at analytics dashboards, this post may save you some false hope.
The symptom
I use PostHog for product analytics across around 20 projects, each one a side project or a small site. Looking at the 30-day reports, the headline visitor numbers looked healthy and, for a few sites, spectacular. One site was up 1,502 percent period over period. Another was up 25,761 percent.
Large percentage jumps on small baselines are normal, so I did not trust them blindly. But the absolute numbers were also big. Across all 20 projects, the 30-day window showed roughly 707,000 visitors. Where did 707,000 people come from?
What I wrongly assumed
I assumed visitors in the dashboard were visitors. That sounds silly written down. But analytics tools present a number labelled “visitors” or “unique users”, and the default behaviour is to count anything that executes your tracking snippet and sends an event. A script that loads a page in a headless browser counts just fine.
I also half-believed my own growth story, because I had done real SEO work on some of these sites. A jump was plausible. I wanted it to be true, which is the worst possible state for evaluating a chart.
How I found out
I stopped looking at the headline and broke traffic down by acquisition channel instead. The question I asked was simple: how many of these visitors came through organic search, and how many arrived as “Direct”?
-- rough shape of the query, run in the analytics SQL editor SELECT session.$channel_type AS channel, count(DISTINCT person_id) AS visitors, count() / count(DISTINCT person_id) AS pageviews_per_visitor FROM events WHERE event = '$pageview' AND timestamp > now() - INTERVAL 30 DAY GROUP BY channel ORDER BY visitors DESC
The result was stark. About 693,000 of the 707,000 visitors, roughly 98 percent, were bots. And they were remarkably easy to describe, because they all looked the same:
- channel: Direct, nearly always
- about 1.00 pageviews per visitor, one page and gone
- bounce rate of 97 to 99 percent
- sessions lasting four to seven seconds
- geography concentrated in a few countries (Singapore, Hong Kong, Mexico, China) with no connection to my audience
- user agents split almost evenly between Chrome on Windows and Chrome on Mac, which is what a spoofed fleet looks like
Real people do not split into two perfectly even groups, and they do not read one page for five seconds then vanish a million times.
Per site, it was worse than the totals. The first site had 546,000 bot visitors in the Direct channel versus 4,500 real organic visitors. The second had 126,000 bot Direct visitors versus one organic visitor. The +25,761 percent growth was a bot flood on a baseline of nothing.
The one place the pattern broke
One of my sites was the exception. Its Direct traffic had a bounce rate under 50 percent, which is a human-like number. Direct visitors there looked like real readers, probably people with bookmarks or links from messaging apps. So the rule is not “ignore Direct.” It is: ignore Direct unless its bounce rate and pages per visitor look human.
A second trap: the broken filter
PostHog has a setting that filters out internal and test users. On one of my projects, that setting was misconfigured in a way that filtered out 100 percent of real traffic. Anything I queried with it enabled showed an empty site. I found it by comparing a filtered and an unfiltered query and getting wildly different answers.
That is the opposite error from the bot problem: there, the tool counted too much; here it counted nothing. Both come from not checking whether the dashboard’s idea of a visitor matches yours.
Why this matters beyond vanity
Bots are not harmless noise. They cost compute. A scraper fleet that hits one page per visitor, from thousands of addresses, sidesteps per-address rate limiting entirely, because each address only makes one request.
A sanity check I now run before believing any traffic number: divide requests by distinct client addresses. If it is close to 1, no per-client limit will save you.
Telling a bot from a real reader in practice
You do not need a bot-detection product to get most of the way there. A few cheap signals combine well, and none of them needs anything beyond the data you already collect:
- Pageviews per visitor. A fleet of one-page visitors is a ratio stuck at exactly 1.0. Real readers wander, even on tiny sites.
- Session duration. Four to seven seconds, over and over, is a script that loads, extracts, and leaves.
- Referrer or channel. Humans arrive from search, from other sites, from newsletters. A site that claims to be 99 percent Direct has an attribution problem or a bot problem.
- Geography that matches nothing. If an English-language hobby site gets half its traffic from a handful of countries it has never been mentioned in, be sceptical.
- Browser mix. Perfectly even splits between two user agents, or user agents several major versions old, are manufactured.
Once you have a rule of thumb, save it as a saved view so you stop re-deriving it. Mine is a filter on channel type and a bounce-rate threshold, and it takes the dashboard from 707,000 visitors to a few thousand that I believe.
What it did to my decisions
Before I looked, I had been tempted to spend time on the sites that showed the most growth, and to feel good about work on the ones that did not. With bots removed, the ranking changed completely. The sites with the biggest numbers had almost no readers, and the quiet ones with a handful of genuine search visitors were the ones actually working. Prioritising by the dashboard would have pointed me at the wrong projects.
What I do now
- Report organic search visitors and their bounce rate, not total visitors. It is a smaller number, and it is the honest one.
- Break every traffic report down by channel before reading the total. A big Direct number with a 99 percent bounce rate is a bot signature.
- Look at pageviews per visitor and session duration. One page and five seconds is not reading.
- Be suspicious of enormous percentage growth on tiny sites. A 25,000 percent jump should prompt a question, not a celebration.
- Check that your filters do what they say. Run the same query with the filter on and off.
- Remember what real success looked like. For one site that was a handful of genuine Google visitors per week. That is the baseline to grow from.
It is a little deflating to discover that 98 percent of your audience is a script. But it is better to know. A site with one real organic visitor is a site where the next real organic visitor is a doubling, and you can only celebrate that if you are counting properly.