I expected crawlers to spend most of their requests on content. The point of a crawl is the content.

ClaudeBot spent 80% of its requests re-reading the rulebook and the map. The way it did it is the interesting part.

Crawl-budget allocation

Split every bot’s requests into four buckets - /robots.txt, /sitemap.xml, content cells, and everything else - over the full 80-day window (2026-05-18 to 2026-08-06, 15,874 canonical hits). The spread across the roster is enormous.

oai-searchbot claudebot gptbot meta-external amazonbot robots.txt sitemap content other
Figure 1 - Share of each bot's requests by target. Two poles: oai-searchbot and claudebot spend almost everything on robots.txt + sitemap; amazonbot and meta-external go almost entirely to content.
class total robots.txt sitemap content meta/content
oai-searchbot 210 189 1 6 31.7
claudebot 871 347 349 157 4.4
googlebot* 615 79 4 29 2.9
applebot 111 22 1 38 0.6
gptbot 298 0 79 171 0.5
seo-tools 601 160 7 419 0.4
bingbot 497 57 25 342 0.2
amazonbot 175 0 3 147 0.0
meta-external 102 0 1 75 0.0

meta/content = robots.txt + sitemap fetches per content fetch. *Googlebot’s total is inflated by a one-day spoof flood on / (a separate story); its real content sample is small.

Two opposite philosophies fall out of the last column. Compliance-heavy, content-light: oai-searchbot (90% robots.txt), claudebot (4.4 meta-fetches per page), googlebot. Content-greedy, rules-blind: amazonbot and meta-external fetched /robots.txt zero times in the entire window and went straight to content. ClaudeBot is the extreme of the first group: 696 combined robots + sitemap fetches against 157 content fetches.

The shape explains the number

The 18%-content figure hides a phase change. Split ClaudeBot’s daily activity into content vs meta (robots + sitemap) and a hard switch appears on 2026-07-05.

03060 last content fetch: 2026-07-05 05-1805-2007-0407-0507-0707-1507-3108-05 contentrobots + sitemap
Figure 2 - ClaudeBot's daily content (blue) vs robots+sitemap (coral). Content collapses to zero after 2026-07-05; the meta heartbeat continues at a steady ~24/day for the next month.

ClaudeBot’s last content fetch was 2026-07-05. Its last robots/sitemap fetch was 2026-08-06, still going at snapshot time. From 2026-07-07 onward it ran an almost perfectly regular 12 robots.txt + 12 sitemap.xml + 0 content, every single day for a month.

The heartbeat is machine-regular

Zoom into one day (2026-07-15) and it is a metronome: robots.txt and sitemap.xml fetched as a pair, in the same second, every ~2 hours.

00:33  robots + sitemap      12:30  robots + sitemap
02:47  robots + sitemap      14:40  robots + sitemap
04:25  robots + sitemap      16:33  robots + sitemap
06:36  robots + sitemap      18:30  robots + sitemap
08:36  robots + sitemap      20:29  robots + sitemap
10:37  robots + sitemap      22:35  robots + sitemap

Twelve pairs, roughly two hours apart, no content in between. Not a crawl - a scheduled freshness poll.

This is real ClaudeBot, not a spoof

ClaudeBot has no public verification manifest, so spoofing is a fair worry. It does not apply here: 861 of 871 ClaudeBot hits come from Amazon / AWS across 51 IPs. Anthropic runs on AWS, and a month of two-hourly clockwork is infrastructure, not a scraper. The 10 stragglers from cheap VPS ranges are the ~1% impersonation noise, not the heartbeat.

What this means for site owners

“ClaudeBot visits my pages regularly” is the wrong mental model. In this window it visited the content once, early, then stopped fetching pages entirely while continuing to hit robots.txt and sitemap.xml every two hours. The poll is not a content re-crawl.

If you want to control Amazonbot or Meta, robots.txt may be the wrong lever - they never fetch it. Zero robots.txt reads across the window for both. Whatever rule-checking they do is not happening on-domain, so a Disallow: they never read cannot be assumed to bind. The only way to know is to disallow and watch the content fetches, not the robots fetches.

What this does not prove

  • One cold-start domain, low popularity, 80 days. The cadence and the front-load-then-heartbeat shape may be specific to how Anthropic treats a new, low-value property. A high-authority site with genuinely changing content could see a different allocation.
  • “Heartbeat ignores freshness” is not established. Content did not change during the heartbeat month, so not re-crawling is the correct action. Whether bumping a page’s lastmod or body mid-heartbeat would pull ClaudeBot back to that page is untested.
  • The 12/day count is unexplained. Why exactly two hours and twelve pairs - fixed interval, per-IP schedule summed across the pool, or coincidence of the window - is unknown.

What would falsify this

Mutate one content cell mid-heartbeat and watch the next two-hourly sitemap poll. If a content fetch of that cell follows, the poll is actionable and “ignores freshness” is wrong. If nothing follows for a week, the decoupling is real. I plan to run exactly that.

Method notes

Bucketing used exact url_path matching for /robots.txt and a LIKE '%sitemap%' match for the sitemap; content is any hit whose rendering_mode is ssr, csr, or ssg. The four-bucket totals per bot come from the canonical Cloudflare-logs ingest (deduplicated by ray_id); the Next.js middleware ingest is excluded to avoid double counting. ASN attribution is from the Cloudflare edge log’s asn field.


Data availability: JS SEO Lab publishes methodology, tracker code, and classifier in the public repository at github.com/Qbeczek1/jsseo-dev. Live dashboard at /dashboard/.

Bias disclosure: I run JS SEO Lab as an independent technical SEO research project. I also do paid technical SEO and AI-visibility audits through FratreSEO. No framework vendor, crawler vendor, search engine, or AI company funds this work.