---
title: "Most &#8220;GPTBot&#8221; Traffic Is Fake: How to Track Real AI Crawlers"
description: "80% of \"GPTBot\" requests in my logs were fake. How to verify AI crawlers against official IP lists, and a free script to check your own logs."
featured_image: "https://phillipstemann.com/wp-content/uploads/2026/10/fake-ai-crawlers-cover-en.png"
url: "https://phillipstemann.com/track-ai-crawlers-server-logs/"
language: "en"
date_published: "2026-10-19T08:00:00+02:00"
date_modified: "2026-10-19T09:46:43+02:00"
---

# Most &#8220;GPTBot&#8221; Traffic Is Fake: How to Track Real AI Crawlers

The first time I searched my server logs for AI crawlers, the picture looked alarming: hundreds of requests from GPTBot, ClaudeBot and PerplexityBot, and most of them ending in errors. It looked like the AI companies were hammering my site and getting nothing.

Then I checked the IP addresses. Most of those “AI crawlers” weren’t AI crawlers at all. They were vulnerability scanners wearing an AI company’s name, looking for passwords and API keys.

Here’s what I found in a week of logs, why it matters for both security and GEO, and the short script I used so you can run the same check on your own site.

**The short version:**

- **80%** of requests calling themselves GPTBot were fake. For Perplexity-User it was **100%**.
- The fakes weren’t crawling content. They were probing for files like .env, cloud credentials and Kubernetes tokens.
- The real crawlers behaved well: almost all their requests succeeded.
- Real ChatGPT-User fetched my pages 56 times in a week, but only 2 visits came from ChatGPT. Analytics only shows you the 2.

## Three kinds of AI bots

Before counting anything, it helps to know that each AI company runs several bots, for different jobs. Blocking or allowing them has different consequences (see [OpenAI’s crawler documentation](https://platform.openai.com/docs/bots) for the details on OpenAI’s).

| Job | OpenAI | Anthropic | Perplexity | What it means for you |
| --- | --- | --- | --- | --- |
| Training | GPTBot | ClaudeBot | – | Your content may end up in future models |
| Search index | OAI-SearchBot | Claude-SearchBot | PerplexityBot | Whether you can show up in AI search answers at all |
| Live fetch for a user | ChatGPT-User | Claude-User | Perplexity-User | Someone asked a question and the AI is reading your page right now |

## What I measured

I took the nginx access logs for phillipstemann.com from 8 to 15 October 2026 (69,015 requests) and compared every request that claimed to be an AI crawler with the IP list its company publishes. A request only counts as real if both the name and the IP match.

| User agent | Claimed | Real | Fake | Fake share |
| --- | --- | --- | --- | --- |
| GPTBot | 137 | 27 | 110 | 80% |
| OAI-SearchBot | 551 | 453 | 98 | 18% |
| ChatGPT-User | 157 | 56 | 101 | 64% |
| ClaudeBot | 285 | 176 | 109 | 38% |
| PerplexityBot | 160 | 51 | 109 | 68% |
| Perplexity-User | 105 | 0 | 105 | 100% |

********

It isn’t only AI names. Running the same check against Google’s published list, 56% of the requests calling themselves Googlebot were fake too.

## What the fakes were doing

The fake requests weren’t reading blog posts. They were going for files that should never be public: `/.env`, `/.env.local`, `/.npmrc`, `/.bashrc`, `/serverless.yml`, `/firebase-credentials.json`, `/proc/self/environ` and paths to Kubernetes service account tokens. On my site those all return 404, which is exactly what you want.

Why pretend to be GPTBot? Because many site owners now allow AI crawlers through their firewall or bot protection so they can show up in AI answers. If that rule only checks the user agent, an attacker gets waved through by typing a name.

**The lesson for security:** never allow a bot based on its user agent alone. If you use Cloudflare, use its verified bot categories instead of user-agent rules. If you write your own rules, check the IP.

## What the real crawlers were doing

The verified crawlers were well behaved. Real ChatGPT-User, PerplexityBot and ClaudeBot requests almost all succeeded, and they fetched the pages you’d hope for: the homepage, my HARO alternatives list, my SEO service page, my Search Console guide and my podcast list. Without the fakes, the “AI crawlers are hitting errors” problem disappeared completely.

## The GEO number analytics can’t show you

This is the part I find most useful. ChatGPT-User only fetches a page when a real person asks ChatGPT something and ChatGPT decides to read that page to answer. In the same week:

- Verified ChatGPT-User fetched **14 of my pages, 56 times**.
- Only **2 visits** arrived from ChatGPT (one with a chatgpt.com referrer, one tagged utm\_source=chatgpt.com).

That’s roughly 28 answers built from my pages for every visit I got. If you only look at analytics, you see the 2 visits and conclude ChatGPT doesn’t matter. The logs show ChatGPT reading your content far more often than it sends anyone. For GEO, live AI fetches per page are a better visibility metric than referral clicks.

## How to run the same check on your site

### 1. Get your access logs

On most hosts they’re in your control panel or your home folder. On CloudPanel they’re in `~/logs/nginx/`, on cPanel under Raw Access. If you’re behind Cloudflare, check two things: that your logs record the visitor’s real IP (Cloudflare passes it in the `CF-Connecting-IP` header), and that the pages you care about aren’t cached at Cloudflare, because cached responses never reach your server.

### 2. Get the official IP lists

Each company publishes the IP ranges its bots use as a small JSON file:

- OpenAI: `CODE_OPEN`openai.com/gptbot.json`CODE_CLOSE`, `CODE_OPEN`openai.com/searchbot.json`CODE_CLOSE`, `CODE_OPEN`openai.com/chatgpt-user.json`CODE_CLOSE`
- Anthropic: `CODE_OPEN`claude.com/crawling/bots.json`CODE_CLOSE`
- Perplexity: `CODE_OPEN`perplexity.com/perplexitybot.json`CODE_CLOSE`, `CODE_OPEN`perplexity.com/perplexity-user.json`CODE_CLOSE`
- Google: `CODE_OPEN`developers.google.com/static/search/apis/ipranges/googlebot.json`CODE_CLOSE`

### 3. Run the script

This is the exact script that produced the table above. It needs only Python 3 and nothing else. It expects the client IP as the last quoted field of each log line, which is how CloudPanel logs it behind Cloudflare; if your format is different, change that one line. Run it with `python3 verify_ai_bots.py access.log`.

```
import ipaddress, json, re, sys, urllib.request
from collections import Counter

# Official IP lists published by each company
LISTS = {
    "GPTBot":          "https://openai.com/gptbot.json",
    "OAI-SearchBot":   "https://openai.com/searchbot.json",
    "ChatGPT-User":    "https://openai.com/chatgpt-user.json",
    "ClaudeBot":       "https://claude.com/crawling/bots.json",
    "PerplexityBot":   "https://www.perplexity.com/perplexitybot.json",
    "Perplexity-User": "https://www.perplexity.com/perplexity-user.json",
}

def load(url):
    data = json.load(urllib.request.urlopen(urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})))
    return [ipaddress.ip_network(p.get("ipv4Prefix") or p.get("ipv6Prefix")) for p in data["prefixes"]]

ranges = {bot: load(url) for bot, url in LISTS.items()}
real, fake = Counter(), Counter()

for line in open(sys.argv[1], errors="replace"):
    for bot in ranges:
        if bot in line:
            ip = re.findall(r'"([0-9a-fA-F.:]+)"\s*$', line)  # client IP as the last quoted field
            ip = ip[0] if ip else line.split()[0]
            ok = any(ipaddress.ip_address(ip) in net for net in ranges[bot])
            (real if ok else fake)[bot] += 1
            break

for bot in ranges:
    total = real[bot] + fake[bot]
    if total:
        print(f"{bot:16} {total:5} claimed  {real[bot]:5} real  {fake[bot]:5} fake ({fake[bot] / total:.0%})")
```

### 4. Look at three things

- **The fake share.** If it’s high, make sure no firewall rule trusts AI user agents.
- **Which pages the real crawlers fetch.** Those are the pages AI tools know you for. If your money pages aren’t on the list, that’s your GEO to-do list.
- **Live fetches (ChatGPT-User, Perplexity-User, Claude-User) per page over time.** That’s the closest thing to an AI visibility metric you can get from your own data.

## Caveats

- One site, one week. Your numbers will be different, which is why it’s worth running yourself.
- The IP lists change. Download them fresh every time; the script does.
- Anthropic’s list is new, so an older guide may still tell you Claude’s IPs can’t be verified. They can now.

If you want this as an ongoing report instead of a one-off script, that’s part of my [tracking and analytics service](/services/tracking/). And if you’re wondering whether any of those crawlers read your llms.txt: [I checked that too](/does-llms-txt-work/).
