Fizzdoc, my free PDF and photo toolkit, has no analytics script. No Google Analytics, no pixel, no cookie banner. The page isn't even allowed to make outside requests: its Content Security Policy blocks every connection that doesn't go back to fizzdoc.com.
That was the point. A tool that promises "your files never leave your device" shouldn't be quietly reporting on you either.
It also means I had no idea who uses it.
The only numbers I have are the ones every host sees anyway: Cloudflare's request logs, summed per day, with no cookies and no fingerprinting. So I took 30 days of them and tried to answer one question: how many of my "visitors" are actually people?
Here's what the dashboard says:
| Last 30 days | |
|---|---|
| Requests | 273,490 |
| Unique visitors | 17,490 |
| Visits | 36,010 |
| Page views | 51,880 |
| Data served | 18.23 GB |
| Server errors (5xx) | 0 |
36,000 visits for a side project sounds amazing. It isn't true. Let's take it apart.
Clue 1: the second most popular file isn't a page
Sort requests by path and the top of the list is:
| Path | Requests |
|---|---|
/ (home page) |
7,690 |
/robots.txt |
2,990 |
/sw.js |
2,750 |
/theme.js |
1,990 |
/manifest.webmanifest |
1,660 |
robots.txt is the second most requested file on the site. No human opens it on purpose. That's 3,000 requests from crawlers asking whether they're allowed in. (They are. I welcome search engines and AI answer engines, because that's how people find a free tool.)
Clue 2: the "browsers" aren't browsers
Cloudflare groups page views by browser. The biggest group isn't Chrome:
| Browser | Page views |
|---|---|
| Unknown / Others | 30,940 |
| Chrome | 10,130 |
| Mobile Safari | 3,780 |
| Googlebot | 1,890 |
| Bingbot | 1,090 |
| Edge | 970 |
| Firefox | 630 |
"Unknown" is three times bigger than Chrome. The user-agent list explains it:
- Petalbot (Huawei's search crawler): 10,290 page views. My single biggest "visitor".
- SemrushBot (an SEO tool): 5,150.
- An iPhone on iOS 13, from 2019, with 2,760 page views. That exact user agent is a favourite of scrapers.
-
msh-pdfmin/1: 2,720. I have no idea what this is. It reads PDFs, apparently. - ElevenLabs' crawler, Amazonbot, Googlebot and Bingbot after that.
Across all requests, 11,790 had no user agent at all, and 14,700 came from Headless Chrome: Chrome with no screen, which is what scrapers and test bots run.
Clue 3: Singapore loves my site (it doesn't)
Page views by country:
| Country | Page views |
|---|---|
| United States | 22,120 |
| Singapore | 12,240 |
| Germany | 2,120 |
| Brazil | 1,730 |
| India | 1,240 |
| France | 1,150 |
| Finland | 1,120 |
Singapore, with six million people, sends ten times more page views than India, where I live and where most people I know use the site.
But the best clue is the ratio of requests to page views, because a real visit pulls in fonts, scripts and, if you use a tool, its engine:
| Country | Requests | Page views | Requests per page |
|---|---|---|---|
| India | 27,400 | 1,240 | 22 |
| United States | 73,110 | 22,120 | 3.3 |
| Singapore | 18,910 | 12,240 | 1.5 |
Indian visitors load 22 files per page: they're opening tools and using them. "Singapore" loads one and a half: fetch the HTML, leave. That's what a crawler in a data centre does, and Singapore is full of data centres.
Clue 4: bots looking for a server that doesn't exist
Fizzdoc has no backend. No database, no login, no API, no WordPress. Bots don't know that, so they keep checking:
| Path | Blocked requests |
|---|---|
/api/ |
60 |
/wp-config.php |
40 |
/wp-config.php.old |
40 |
/settings |
40 |
/login |
20 |
/wp-config.php.bak |
20 |
wp-config.php is where WordPress keeps its database password, and .old and .bak are the backup copies people forget to delete. Someone is checking my static site for all three.
Add the rest of the guessing and 30,650 requests got a 4xx error: one in nine requests was for something that never existed.
My favourite part of having no backend: none of this matters. There's nothing to find.
So how many people? Count the downloads, not the visits
Page views are easy to fake. Downloading an AI model is not, and bots don't bother, because they never run the tool.
Fizzdoc's AI tools download a model the first time you use them, and the browser keeps it afterwards. So the bandwidth spent on model files is a rough count of real people who actually used an AI tool:
- Phone background removal. The model is 4.57 MB and served 1.19 GB: about 260 downloads.
- Desktop background removal. The model is about 100 MB, split into 20 MB parts because Cloudflare Pages won't host a file over 25 MB. Each part served 1 to 1.7 GB: roughly 50 to 80 full downloads.
- Speech to text. The encoder is 10 MB and served 608 MB: about 60 transcriptions.
These are rough. A download that stops halfway still counts, and one person on two devices counts twice. But the scale is clear: tens of thousands of "visits" in the dashboard, a few hundred real uses of the heavy tools. Add the people using light tools that need no model (compress, merge, convert) and the real number of people is in the low thousands, close to the 17,490 "unique visitors" at best, and nowhere near 36,000 visits.
Honestly? A few thousand people a month trusting a side project with their files is more than I expected. I just wanted the real number.
Bonus: my CDN wasn't caching my heaviest files
One more number bothered me: only 41.65% of requests came from Cloudflare's cache, and only 11.82% of the bandwidth (2.15 GB of 18.23 GB).
For a site that is 100% static files, that's low. The headers explain it:
$ curl -sI https://fizzdoc.com/assets/index-....js
cache-control: public, max-age=31536000, immutable <- cached for a year
$ curl -sI https://fizzdoc.com/bg/birefnet-lite/model.onnx.part0
cache-control: public, max-age=0, must-revalidate <- re-checked every time
cf-cache-status: DYNAMIC
The JavaScript is cached perfectly. Its filename contains a hash of its contents, so it can be cached "forever". But the model files, the heaviest files on the site, had no cache rule, so 16 GB went out uncached.
Visitors barely noticed, because the browser keeps a model after the first download. But it's the wrong default, and it's a few lines in a _headers file. That's the next post: the fix, and the before and after.
What I learned
- Dashboard visits are not people. On a small site, bots can easily be most of the traffic. Don't put "36k visits" on a slide.
-
Your top paths are a free bot report.
robots.txt,wp-config.phpand 404s tell you who's knocking. - Requests per page view is a great bot detector. People load assets; crawlers fetch HTML and leave.
- Count something bots can't fake. For me it's model downloads. For you it might be a form submit, an export or a signup.
- You don't need tracking to learn a lot. Aggregate server-side numbers answered most of my questions without a single cookie.
- Check your cache headers. A static site with a 42% cache hit rate has a config bug, not a traffic problem.
Fizzdoc is free and open source. It runs 74 PDF, photo and audio tools entirely in your browser, in 17 languages.
- Try it: fizzdoc.com
- Code: github.com/kingrishabdugar/fizzdoc
If you've been through your own logs and found something weird, tell me in the comments. And if you think my real-human estimate is too high or too low, I'd love to know how you'd measure it.
Originally published on my blog.






Top comments (0)