Dev.to WebDev 🛠 Dev 👁 0 📖 2 min read

Most of the AI traffic in our logs was fake. So we had to build a system to tell it apart

Every Monday we asked three things about one small site: who read it last week, was that good, and what should we write next. Then we added the question everyone with a content site is asking now: are AI assistants readi

Every Monday we asked three things about one small site: who read it last week, was that good, and what should we write next. Then we added the question everyone with a content site is asking now: are AI assistants reading us?

Counting user-agents said yes, plenty. Then we checked who was behind them.

Scanners wear AI user-agents. In 30 days of our nginx log, 217 of the 221 ChatGPT-User requests from outside OpenAI's published IP list came from addresses that also probed for scanner paths like /.env and wp-login.php. Every request claiming to be DeepSeekBot, CCBot, Grok, Perplexity-User or Claude-SearchBot was fake.

OpenAI, Anthropic, Perplexity, Apple, Google and Bing all publish the IP ranges their crawlers use. A request that claims to be one of their agents from outside that list is not theirs:

$ npx siteread check 203.0.113.9 "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; ChatGPT-User/1.0; +https://openai.com/bot"
spoofed   203.0.113.9 claims chatgpt-user (chatgpt, answer) but is not in openai.com/chatgpt-user.json (234 prefixes)

The rule of thumb that called a real ClaudeBot fake. Before using the lists, our test was "an IP that ever hit a scanner path is a scanner." Then ClaudeBot followed a GitHub README's relative links onto our domain, asked for a path that does not exist, drew one 444, and all 50 of its reads that day were counted as spoofed. Every real ClaudeBot IP was in Anthropic's published list. So siteread has one rule: where a vendor list exists, the list decides.

Two more from the log: Claude Code's WebFetch sends Claude-User (claude-code/…) from the user's own machine, so no list can cover it; and Google-Extended is a robots.txt token, never a real user-agent.

From a checker to a weekly read. siteread digest turns a Search Console export and your access logs into one JSON document: Search Console weeks with impression-weighted position, people by where their first visit came from, every crawler verified against its vendor's list, and goals you name. The seo-read skill for Claude Code writes that up as a dated weekly memo with two to four things to do next.

It runs on your machine, Node 20+, zero dependencies. No hostnames, URLs or visitor IPs leave it. The optional siteread share sends one week of totals to a public benchmark, prints every byte first, and sends nothing without a yes.

Try it:

npx siteread check <ip> "<user-agent>"
npx siteread digest --gsc export.zip --log access.log --out .siteread/digests

The full story, the benchmark and the docs: https://siteread.dev/blog/introducing-siteread

MIT licensed, source at https://github.com/synacl-iot/siteread. A log line it gets wrong is the most useful issue you can send.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.