One IP claimed to be Google, OpenAI, Anthropic, Apple and Meta - while hunting for our .env file
Table of contents
A reader-style objection to our own data: when the tracker marks a PerplexityBot hit “unverified,” maybe that is our failure to recognise legitimate traffic - a stale IP manifest, or vendor stealth-crawling from undisclosed IPs. Perplexity has a documented history of exactly that. So we went looking for our mistake.
We did not find our mistake. We found a costume rack.
How verification works here
For Perplexity and OpenAI the tracker checks the source IP against the vendor’s own published manifest (perplexity.ai/perplexitybot.json, OpenAI’s ranges). For Google, Bing and Apple it does reverse-DNS with forward confirmation. verified = 1 means the IP is in the vendor’s published infrastructure; verified = 0 means it is not.
Over the 80-day window, the spoof rates for the classes that can be checked:
| class | total | verified | fake | % fake |
|---|---|---|---|---|
| google-extended | 6 | 0 | 6 | 100% |
| perplexitybot | 30 | 3 | 27 | 90% |
| chatgpt-user | 27 | 3 | 24 | 89% |
| oai-searchbot | 218 | 189 | 29 | 13% |
| applebot | 152 | 133 | 19 | 12% |
| gptbot | 666 | 647 | 19 | 3% |
| bingbot | 856 | 841 | 15 | 2% |
The objection says: maybe that 90% is our blind spot. Two behavioural signals, independent of the IP check, close that door.
Proof one: impossible identity
The fake AI-fetcher hits trace to a pool of nine cheap-VPS IPs, each rotating up to twelve distinct crawler identities. One address, 45.87.41.224 (SpectraIP, Netherlands), presented as all of these:
Proof two: intent
The same IPs are not indexing. They hunt for secrets: /.env, /.env.backup, /gcp-credentials.json, /service-account.json, /serviceAccountKey.json, /docker-compose.yml, /graphql/console. No legitimate AI crawler scans for service-account keys. This is credential scanning wearing a bot costume.
Share of each class’s fakes that traces to this nine-IP pool: perplexitybot 27/27, chatgpt-user 24/24, oai-searchbot 29/29, gptbot 19/19, google-extended 6/6, applebot 18/19. In this dataset the entire apparent Perplexity / ChatGPT-User / OpenAI-search presence is one small impersonation pool.
The real ones are cleanly separable
Every verified = 1 Perplexity hit came from Amazon / AWS (Perplexity’s real infrastructure), fetched /robots.txt and content normally, and matched the published perplexitybot.json manifest. The manifest verified those AWS IPs correctly, so the “fakes” are not a broken-manifest false negative. Real Perplexity showed up a handful of times and behaved. The costume rack did the rest.
Cloudflare only vets Googlebot
One more asymmetry. Of the fake Googlebot hits, 436 of 453 got a 403 - Cloudflare’s managed reverse-DNS verification catches and blocks them. The fake Perplexity, ChatGPT-User, OAI-SearchBot, GPTBot and Applebot hits got zero 403s. They passed through as ordinary 200s. Cloudflare hard-verifies Google; the rest are on you.
(The Googlebot fakes are a separate event from the nine-IP pool: 435 of 455 came in a single day, 2026-07-31, from one Dutch hosting ASN flooding / with ~3,000 requests. Different actor, same lesson.)
What this means for site owners
Counting “AI crawler visits” by user-agent is wrong, and wrong in a specific direction. For Perplexity and ChatGPT-User the raw UA count is roughly ten times the verified count. A dashboard reporting “Perplexity crawled you 300 times” is very likely showing a scanner in a Perplexity costume for most of them. GPTBot and Bingbot, which publish verifiable ranges, are only 2-3% inflated - trust those.
Three checks, any one strong, all three dispositive:
- IP-range / rDNS against the vendor’s published manifest.
- Behaviour - anything scanning for
.envor service-account keys is not a real AI crawler. - Per-IP UA rotation - group by source IP, count distinct vendor identities. One IP claiming to be Google and OpenAI and Anthropic is your fastest smoking gun in a client log.
What this does not prove
- The pool is small in absolute terms (~198 hits) on a low-traffic cold-start domain. The ratio and the behaviour are the finding; absolute counts differ on a bigger site.
- It does not identify who runs the pool. The ASNs (Hostodo, Infraly, SpectraIP, Advin, Contabo) are the packet origin, not the actor.
- It does not rule out genuine vendor stealth-crawling in general - only in this window, where no clean-behaving unverified fetch exists to support that reading.
Method notes
Raw IP is retained only for verified = 0 rows (for forensics) and nulled for verified bots (anonymised) - so the per-IP costume analysis is possible precisely because these failed verification. UA classification is regex; verification is IP-range (ip-range method) or reverse-DNS (rdns). The nine-IP pool is defined as distinct source IPs presenting two or more vendor bot classes.
Data availability: methodology, tracker code and classifier are public at github.com/Qbeczek1/jsseo-dev.
Bias disclosure: I run JS SEO Lab as an independent technical SEO research project, and do paid technical SEO and AI-visibility audits through FratreSEO. No crawler vendor, search engine, or AI company funds this work.