<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Crawlerpeek]]></title><description><![CDATA[Open-source tools that show how AI crawlers and search bots see your website. Data from our own server logs. Free checker at crawlerpeek.com]]></description><link>https://crawlerpeek.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 27 Oct 2026 14:08:22 GMT</lastBuildDate><atom:link href="https://crawlerpeek.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Is that really GPTBot? What a week of server logs says about AI crawler claims]]></title><description><![CDATA[One week of server logs: how many requests claiming to be GPTBot, Googlebot or PerplexityBot came from their real IP ranges and how to check your site]]></description><link>https://crawlerpeek.hashnode.dev/is-that-really-gptbot-ai-crawler-claims</link><guid isPermaLink="true">https://crawlerpeek.hashnode.dev/is-that-really-gptbot-ai-crawler-claims</guid><category><![CDATA[SEO]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[mcp]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Crawlerpeek]]></dc:creator><pubDate>Sun, 25 Oct 2026 21:26:52 GMT</pubDate><content:encoded><![CDATA[<p>I maintain a small CLI called crawlerpeek that checks whether AI crawlers can reach a site. While building it I wanted to know how much of the "bot traffic" in my own logs is what it says it is. This post has the numbers, what they do and do not show, and then how to run the same kind of check on your site.</p>
<h2>What I measured</h2>
<p>Period: 19 to 25 October 2026. Four new, small sites that I operate. For every request whose user agent contains a bot token, I checked whether the client IP lies inside the IP list that the operator publishes (Google, OpenAI, Anthropic, Perplexity, Bing, Apple, Common Crawl, Ahrefs), fetched the same day. I removed my own server's requests and my own manual tests.</p>
<table>
<thead>
<tr>
<th>Claimed bot</th>
<th>In published ranges</th>
<th>Share</th>
</tr>
</thead>
<tbody><tr>
<td>OAI-SearchBot</td>
<td>2,315 of 2,356</td>
<td>98%</td>
</tr>
<tr>
<td>Googlebot</td>
<td>1,923 of 2,003</td>
<td>96%</td>
</tr>
<tr>
<td>ClaudeBot</td>
<td>719 of 748</td>
<td>96%</td>
</tr>
<tr>
<td>GPTBot</td>
<td>493 of 524</td>
<td>94%</td>
</tr>
<tr>
<td>ChatGPT-User</td>
<td>162 of 200</td>
<td>81%</td>
</tr>
<tr>
<td>Bingbot</td>
<td>133 of 168</td>
<td>79%</td>
</tr>
<tr>
<td>PerplexityBot</td>
<td>12 of 54</td>
<td>22%</td>
</tr>
<tr>
<td>CCBot</td>
<td>0 of 36</td>
<td>0%</td>
</tr>
</tbody></table>
<p>Applebot and AhrefsBot were 100%.</p>
<p>There were 332 requests that did not match. 287 of them came from a single hosting network, and that network claimed eight different bots: Bingbot, CCBot, ChatGPT-User, ClaudeBot, Googlebot, GPTBot, OAI-SearchBot and PerplexityBot. Its reverse DNS did not confirm forward. A further 45 had no reverse DNS at all.</p>
<h2>What this does not show</h2>
<ul>
<li>It is one week on four new, small sites. Bigger or older sites will see a different mix.</li>
<li>Published IP lists can lag behind new crawler addresses. "Unverified" means "not in the list", not "proven fake". The PerplexityBot and ChatGPT-User numbers in particular could be partly list lag.</li>
<li>One host claiming eight unrelated crawlers from non-operator addresses is hard to explain as anything but user-agent spoofing. That is the only claim here I would call solid.</li>
</ul>
<p>The practical point: a user-agent string is a claim, not an identity. If you decide anything based on it (allow, block, rate limit, count it in analytics), the operator's IP list or reverse DNS is the check that matters. Google and others document reverse-DNS verification, and OpenAI, Anthropic, Perplexity, Bing, Apple and Common Crawl publish JSON lists of ranges.</p>
<h2>The other half: what do real bots get from your site?</h2>
<p>Separately from spoofing, there is a more common problem: robots.txt says one thing and the server does another. A WAF rule returns 403 to a user agent that robots.txt allows. A redirect sends a bot to a login page. A <code>User-agent: *</code> group blocks a path, and a bot-specific group further down quietly overrides it (a bot with its own group ignores the <code>*</code> group).</p>
<p>crawlerpeek checks both layers for each bot: the robots.txt decision under RFC 9309 matching rules, and what the page returns when fetched with that bot's user agent.</p>
<pre><code class="language-sh">npx crawlerpeek check https://example.com
</code></pre>
<p>Example output for a site with a WAF rule and a restrictive robots.txt:</p>
<pre><code class="language-plaintext">https://example.com
robots.txt: ok (HTTP 200) at https://example.com/robots.txt

Bot                 robots    HTTP
GPTBot              blocked   200  FAIL
ClaudeBot           allowed   403 (block page)  FAIL
Google-Extended     allowed   -
</code></pre>
<p>Here GPTBot is closed by robots.txt even though the server would answer, and ClaudeBot is allowed by robots.txt but gets a block page. Both are things you would want to know before wondering why a product is never cited.</p>
<p>More forms:</p>
<pre><code class="language-sh">npx crawlerpeek check https://example.com/pricing --bots GPTBot,ClaudeBot --fail-on blocked
npx crawlerpeek check https://example.com --bots all --json
npx crawlerpeek check https://example.com --no-http          # robots.txt only
npx crawlerpeek see https://example.com --bot ClaudeBot      # one bot, full detail
</code></pre>
<p>One limit matters for the topic of this post: crawlerpeek sends the bot's user-agent string from your machine. It is not the real bot and does not come from the operator's IPs. If your site verifies bot IPs, a request that only claims to be Googlebot may be blocked, so a 403 for <code>Googlebot</code> can be correct. A 403 for an unusual bot while a browser gets 200 usually points at a WAF or CDN rule.</p>
<h2>Put it in CI</h2>
<p>Exit code 0 means ok, 1 means the <code>--fail-on</code> condition was met, 2 means a usage or request error. Unknown options are an error, so a typo like <code>--failon</code> cannot pass a build silently.</p>
<p>With the composite action:</p>
<pre><code class="language-yaml">- uses: crawlerpeek/crawlerpeek/action@v0
  with: { url: "https://example.com", fail-on: blocked }
</code></pre>
<p>Or call the CLI yourself after a deploy:</p>
<pre><code class="language-yaml">- run: npx crawlerpeek check https://example.com --fail-on blocked
</code></pre>
<p><code>--fail-on blocked</code> fails when robots.txt closes the path for a bot, or the page answers that bot with 401, 403, 406, 451 or a challenge page. <code>any-non-200</code> is stricter and also fails on 404, 5xx and redirects that end elsewhere. Run it against the pages you care about, not only the home page.</p>
<p>A robots.txt that cannot be fetched is reported as <code>unknown</code> and does not count as blocked. Under RFC 9309 a 5xx robots.txt means "disallow all" for many crawlers, so treat <code>unknown</code> as something to fix.</p>
<h2>Use it from Claude Code, Cursor or another MCP client</h2>
<p><code>crawlerpeek mcp</code> starts an MCP server over stdio with three read-only tools: <code>check_ai_access</code>, <code>see_as_bot</code> and <code>generate_robots_txt</code>. It calls no LLM; the tools only fetch the URL you give them, and results are cached for 10 minutes.</p>
<pre><code class="language-json">{ "mcpServers": { "crawlerpeek": { "command": "npx", "args": ["-y", "crawlerpeek", "mcp"] } } }
</code></pre>
<p>Then you can ask your assistant "can ClaudeBot read /pricing on my staging site?" and it runs the check instead of guessing. It is also listed in the official MCP Registry as <code>io.github.crawlerpeek/crawlerpeek</code>.</p>
<p>To generate a robots.txt that names the AI crawlers explicitly:</p>
<pre><code class="language-sh">npx crawlerpeek robots --disallow /admin/,/cart/ --sitemap https://example.com/sitemap.xml
</code></pre>
<p>Disallowed paths are repeated inside each bot's group on purpose, for the reason above.</p>
<h2>Safety</h2>
<p>One request per bot plus one for robots.txt, sequential, with a 300 ms pause; a 10 second timeout; at most 5 redirects, each re-checked; bodies capped at 2 MB; no cookies. Private, loopback and metadata addresses are refused after DNS resolution, as are ports other than 80 and 443.</p>
<h2>Feedback</h2>
<p>Source is MIT on GitHub: <a href="https://github.com/crawlerpeek/crawlerpeek">https://github.com/crawlerpeek/crawlerpeek</a>. Package: <a href="https://www.npmjs.com/package/crawlerpeek">https://www.npmjs.com/package/crawlerpeek</a> (0.1.2). I would like to hear about missing bots, wrong user-agent strings and false block-page detections. Issues are open.</p>
]]></content:encoded></item></channel></rss>