<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: crawlerpeek</title>
    <description>The latest articles on DEV Community by crawlerpeek (@crawlerpeek).</description>
    <link>https://dev.to/crawlerpeek</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4207334%2F2894a1cb-0ed4-4cfb-9d67-e079e5d2987c.png</url>
      <title>DEV Community: crawlerpeek</title>
      <link>https://dev.to/crawlerpeek</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crawlerpeek"/>
    <language>en</language>
    <item>
      <title>Is that really GPTBot? What a week of server logs says about AI crawler claims</title>
      <dc:creator>crawlerpeek</dc:creator>
      <pubDate>Sun, 25 Oct 2026 21:15:26 +0000</pubDate>
      <link>https://dev.to/crawlerpeek/is-that-really-gptbot-what-a-week-of-server-logs-says-about-ai-crawler-claims-3lpa</link>
      <guid>https://dev.to/crawlerpeek/is-that-really-gptbot-what-a-week-of-server-logs-says-about-ai-crawler-claims-3lpa</guid>
      <description>&lt;p&gt;I maintain a small CLI called crawlerpeek that checks whether AI crawlers can&lt;br&gt;
reach a site. While building it I wanted to know how much of the "bot traffic"&lt;br&gt;
in my own logs is what it says it is. This post has the numbers, what they do&lt;br&gt;
and do not show, and then how to run the same kind of check on your site.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I measured
&lt;/h2&gt;

&lt;p&gt;Period: 19 to 25 October 2026. Four new, small sites that I operate. For every&lt;br&gt;
request whose user agent contains a bot token, I checked whether the client IP&lt;br&gt;
lies inside the IP list that the operator publishes (Google, OpenAI, Anthropic,&lt;br&gt;
Perplexity, Bing, Apple, Common Crawl, Ahrefs), fetched the same day. I removed&lt;br&gt;
my own server's requests and my own manual tests.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Claimed bot&lt;/th&gt;
&lt;th&gt;In published ranges&lt;/th&gt;
&lt;th&gt;Share&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OAI-SearchBot&lt;/td&gt;
&lt;td&gt;2,315 of 2,356&lt;/td&gt;
&lt;td&gt;98%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Googlebot&lt;/td&gt;
&lt;td&gt;1,923 of 2,003&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ClaudeBot&lt;/td&gt;
&lt;td&gt;719 of 748&lt;/td&gt;
&lt;td&gt;96%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPTBot&lt;/td&gt;
&lt;td&gt;493 of 524&lt;/td&gt;
&lt;td&gt;94%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ChatGPT-User&lt;/td&gt;
&lt;td&gt;162 of 200&lt;/td&gt;
&lt;td&gt;81%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bingbot&lt;/td&gt;
&lt;td&gt;133 of 168&lt;/td&gt;
&lt;td&gt;79%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PerplexityBot&lt;/td&gt;
&lt;td&gt;12 of 54&lt;/td&gt;
&lt;td&gt;22%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CCBot&lt;/td&gt;
&lt;td&gt;0 of 36&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Applebot and AhrefsBot were 100%.&lt;/p&gt;

&lt;p&gt;There were 332 requests that did not match. 287 of them came from a single&lt;br&gt;
hosting network, and that network claimed eight different bots: Bingbot, CCBot,&lt;br&gt;
ChatGPT-User, ClaudeBot, Googlebot, GPTBot, OAI-SearchBot and PerplexityBot.&lt;br&gt;
Its reverse DNS did not confirm forward. A further 45 had no reverse DNS at all.&lt;/p&gt;
&lt;h2&gt;
  
  
  What this does not show
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It is one week on four new, small sites. Bigger or older sites will see a
different mix.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The practical point: a user-agent string is a claim, not an identity. If you&lt;br&gt;
decide anything based on it (allow, block, rate limit, count it in analytics),&lt;br&gt;
the operator's IP list or reverse DNS is the check that matters. Google and&lt;br&gt;
others document reverse-DNS verification, and OpenAI, Anthropic, Perplexity,&lt;br&gt;
Bing, Apple and Common Crawl publish JSON lists of ranges.&lt;/p&gt;
&lt;h2&gt;
  
  
  The other half: what do real bots get from your site?
&lt;/h2&gt;

&lt;p&gt;Separately from spoofing, there is a more common problem: robots.txt says one&lt;br&gt;
thing and the server does another. A WAF rule returns 403 to a user agent that&lt;br&gt;
robots.txt allows. A redirect sends a bot to a login page. A &lt;code&gt;User-agent: *&lt;/code&gt;&lt;br&gt;
group blocks a path, and a bot-specific group further down quietly overrides it&lt;br&gt;
(a bot with its own group ignores the &lt;code&gt;*&lt;/code&gt; group).&lt;/p&gt;

&lt;p&gt;crawlerpeek checks both layers for each bot: the robots.txt decision under RFC&lt;br&gt;
9309 matching rules, and what the page returns when fetched with that bot's&lt;br&gt;
user agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx crawlerpeek check https://example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output for a site with a WAF rule and a restrictive robots.txt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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   -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here GPTBot is closed by robots.txt even though the server would answer, and&lt;br&gt;
ClaudeBot is allowed by robots.txt but gets a block page. Both are things you&lt;br&gt;
would want to know before wondering why a product is never cited.&lt;/p&gt;

&lt;p&gt;More forms:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx crawlerpeek check https://example.com/pricing &lt;span class="nt"&gt;--bots&lt;/span&gt; GPTBot,ClaudeBot &lt;span class="nt"&gt;--fail-on&lt;/span&gt; blocked
npx crawlerpeek check https://example.com &lt;span class="nt"&gt;--bots&lt;/span&gt; all &lt;span class="nt"&gt;--json&lt;/span&gt;
npx crawlerpeek check https://example.com &lt;span class="nt"&gt;--no-http&lt;/span&gt;          &lt;span class="c"&gt;# robots.txt only&lt;/span&gt;
npx crawlerpeek see https://example.com &lt;span class="nt"&gt;--bot&lt;/span&gt; ClaudeBot      &lt;span class="c"&gt;# one bot, full detail&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One limit matters for the topic of this post: crawlerpeek sends the bot's&lt;br&gt;
user-agent string from your machine. It is not the real bot and does not come&lt;br&gt;
from the operator's IPs. If your site verifies bot IPs, a request that only&lt;br&gt;
claims to be Googlebot may be blocked, so a 403 for &lt;code&gt;Googlebot&lt;/code&gt; can be correct.&lt;br&gt;
A 403 for an unusual bot while a browser gets 200 usually points at a WAF or CDN&lt;br&gt;
rule.&lt;/p&gt;
&lt;h2&gt;
  
  
  Put it in CI
&lt;/h2&gt;

&lt;p&gt;Exit code 0 means ok, 1 means the &lt;code&gt;--fail-on&lt;/code&gt; condition was met, 2 means a usage&lt;br&gt;
or request error. Unknown options are an error, so a typo like &lt;code&gt;--failon&lt;/code&gt; cannot&lt;br&gt;
pass a build silently.&lt;/p&gt;

&lt;p&gt;With the composite action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;crawlerpeek/crawlerpeek/action@v0&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://example.com"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;fail-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;blocked&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or call the CLI yourself after a deploy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx crawlerpeek check https://example.com --fail-on blocked&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--fail-on blocked&lt;/code&gt; fails when robots.txt closes the path for a bot, or the page&lt;br&gt;
answers that bot with 401, 403, 406, 451 or a challenge page. &lt;code&gt;any-non-200&lt;/code&gt; is&lt;br&gt;
stricter and also fails on 404, 5xx and redirects that end elsewhere. Run it&lt;br&gt;
against the pages you care about, not only the home page.&lt;/p&gt;

&lt;p&gt;A robots.txt that cannot be fetched is reported as &lt;code&gt;unknown&lt;/code&gt; and does not count&lt;br&gt;
as blocked. Under RFC 9309 a 5xx robots.txt means "disallow all" for many&lt;br&gt;
crawlers, so treat &lt;code&gt;unknown&lt;/code&gt; as something to fix.&lt;/p&gt;
&lt;h2&gt;
  
  
  Use it from Claude Code, Cursor or another MCP client
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;crawlerpeek mcp&lt;/code&gt; starts an MCP server over stdio with three read-only tools:&lt;br&gt;
&lt;code&gt;check_ai_access&lt;/code&gt;, &lt;code&gt;see_as_bot&lt;/code&gt; and &lt;code&gt;generate_robots_txt&lt;/code&gt;. It calls no LLM; the&lt;br&gt;
tools only fetch the URL you give them, and results are cached for 10 minutes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"crawlerpeek"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"crawlerpeek"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can ask your assistant "can ClaudeBot read /pricing on my staging&lt;br&gt;
site?" and it runs the check instead of guessing. It is also listed in the&lt;br&gt;
official MCP Registry as &lt;code&gt;io.github.crawlerpeek/crawlerpeek&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To generate a robots.txt that names the AI crawlers explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx crawlerpeek robots &lt;span class="nt"&gt;--disallow&lt;/span&gt; /admin/,/cart/ &lt;span class="nt"&gt;--sitemap&lt;/span&gt; https://example.com/sitemap.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disallowed paths are repeated inside each bot's group on purpose, for the reason&lt;br&gt;
above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety
&lt;/h2&gt;

&lt;p&gt;One request per bot plus one for robots.txt, sequential, with a 300 ms pause; a&lt;br&gt;
10 second timeout; at most 5 redirects, each re-checked; bodies capped at 2 MB;&lt;br&gt;
no cookies. Private, loopback and metadata addresses are refused after DNS&lt;br&gt;
resolution, as are ports other than 80 and 443.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;Source is MIT on GitHub: &lt;a href="https://github.com/crawlerpeek/crawlerpeek" rel="noopener noreferrer"&gt;https://github.com/crawlerpeek/crawlerpeek&lt;/a&gt;. Package:&lt;br&gt;
&lt;a href="https://www.npmjs.com/package/crawlerpeek" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/crawlerpeek&lt;/a&gt; (0.1.2). I would like to hear about&lt;br&gt;
missing bots, wrong user-agent strings and false block-page detections. Issues&lt;br&gt;
are open.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>webdev</category>
      <category>node</category>
      <category>mcp</category>
    </item>
  </channel>
</rss>
