Guide

Server logs and AI crawlers, seeing who really visits your site

Your server logs are the only source that records every AI crawler request, with the URL fetched, the HTTP status returned and the exact time. We show how to read them, how to separate scheduled crawling from user-triggered fetches, and how to check that an agent is really who it claims to be.

Timothé Merle17 min readUpdated September 1, 2026
In short

An AI crawler leaves a line in your server logs on every request, with the URL, the HTTP status, the bytes served and the timestamp. That is the only exhaustive measurement you have, because neither GA4 nor Search Console sees these visits. Three families share the same file, scheduled crawling that feeds an index or model training, user-triggered fetching that does not always follow robots.txt, and human traffic referred from an AI answer, which shows up in the referer rather than the user agent. The user agent proves nothing on its own since it can be spoofed, so match it against the IP ranges each vendor publishes or run a reverse DNS check. What matters next is a short list of numbers, frequency per agent, coverage of your priority pages, and the share of 403, 404 and 429 responses served to agents.

Direct answer

How do you know which pages AI crawlers visit?

Read your server logs. Every request writes one line with the client IP, the timestamp, the requested URL, the HTTP status and the user agent. Filter that file on known AI agent tokens, count lines per agent and per URL, and you get crawl frequency, the pages that are fetched, and the ones that never are.

No other tool gives you that view. Search Console only reports Googlebot, GA4 only measures a human visitor whose browser runs JavaScript, and AI crawlers generally do not run any. Logs record the request at the server level, before rendering and before any analytics consent. They are also the only source that can tell you an important page has never been requested at all, which no citation dashboard can do.

The work splits into four steps, and each answers a different question.

  • Collect. Confirm your entry layer actually writes the user agent and the HTTP status, which is not guaranteed by default on every platform.
  • Filter. Isolate lines whose user agent contains a known AI agent token, case insensitive.
  • Aggregate. Count visits per agent, per URL and per status code, then record the last seen date for every page.
  • Verify. Match client IPs against the ranges the vendor publishes before drawing any conclusion about an agent identity.

Before you open the log file. AI crawler access checker | AI crawler simulator

Distinction

Scheduled crawling, user-triggered fetches, referred humans

Three very different things land in the same log file, and mixing them up ruins the analysis. Scheduled crawling is planned by the vendor, it walks the site without any person asking for it, and it feeds either a search index or a training dataset. A user-triggered fetch starts from a question asked inside an assistant, it touches only a handful of URLs, and it is usually immediate. Referred human traffic is not a robot at all, it is a person who clicked a citation link in an AI answer, and it shows up in the referer field rather than the user agent.

Vendor documentation owns that split. OpenAI separates OAI-SearchBot, used to surface websites in ChatGPT search features, GPTBot, which serves the foundation models, and ChatGPT-User, used for certain user actions. Anthropic splits ClaudeBot, Claude-SearchBot and Claude-User the same way. Perplexity contrasts PerplexityBot, which powers search, with Perplexity-User, which answers an action inside the product.

That nuance has a direct consequence for robots.txt. OpenAI writes that robots.txt rules may not apply because the actions are initiated by a user, Perplexity states that Perplexity-User generally ignores robots.txt rules, and Google says the same about its user-triggered fetchers. Seeing one of those agents despite a blocking rule is therefore not necessarily an incident, it is documented behaviour.

The three AI agent families plus referred human traffic, checked against vendor documentation in August 2026
FamilyUser agent tokensTriggerrobots.txt
Search crawlingOAI-SearchBot, PerplexityBot, Claude-SearchBotScheduled by the vendorFollowed
Training crawlingGPTBot, ClaudeBotScheduled by the vendorFollowed
User-triggered fetchChatGPT-User, Perplexity-User, Claude-UserA question asked in the assistantMay not apply
Referred humanRegular browser, referer chatgpt.comClick on a citation linkNot applicable

OpenAI, crawlers and bots | Anthropic, web crawling | Perplexity, crawlers | Google, user-triggered fetchers

Format

Which log fields do you actually need?

The combined format is enough to start, as long as you add response time. Nginx defines it out of the box with the client address, the user, the local time, the request line, the status, the body bytes, the referer and the user agent. Only one genuinely useful field is missing for crawl diagnosis, processing time, available through the request_time variable that the documentation describes as request processing time in seconds with a milliseconds resolution.

Apache exposes the same set of fields through its LogFormat directive. Its combined format carries the host, the timestamp, the request, the final status and both the Referer and User-Agent headers. Two additions are worth making, duration in microseconds with the D specifier, and bytes actually sent including headers with the O specifier, which requires the mod_logio module.

Nginx documentation showing the combined log format and the request_time variable
Official nginx documentation, the predefined combined format and the status, time_local and request_time variables. Source, nginx.org.
nginx, enriched format
# nginx.conf, le format combined enrichi de la latence de réponse
log_format ai_agents '$remote_addr - $remote_user [$time_local] '
                     '"$request" $status $body_bytes_sent '
                     '"$http_referer" "$http_user_agent" $request_time';

access_log /var/log/nginx/access.log ai_agents;

nginx, ngx_http_log_module | Apache, log files | Apache, mod_log_config

Apache

The same log under Apache

Under Apache the logic is identical and only the syntax changes. Declare a named format, then point CustomLog at it. Keep the final status with the greater-than modifier, otherwise an internal redirect makes you record the status of the original request rather than the one actually served.

Apache, enriched format
# httpd.conf, combined enrichi des octets réels et de la durée
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %D" ai_agents
CustomLog logs/access_log ai_agents
Queries

Reusable filters and queries

These commands carry no customer data and work on any combined format file. Field 9 is the HTTP status and field 7 is the requested URL in that format, which makes aggregation direct. Adapt the token list to your market, an English language site will mostly see OpenAI, Google, Perplexity, Anthropic and Microsoft.

The sixth command is the most useful and the least often run. It compares the URLs actually fetched against your list of priority pages and returns the difference, in other words the pages no AI agent has ever come for. Content that is never crawled cannot be indexed or cited, whatever its editorial quality.

Shell filters on a combined access.log
AI='GPTBot|OAI-SearchBot|ChatGPT-User|ClaudeBot|Claude-User|Claude-SearchBot|PerplexityBot|Perplexity-User|Googlebot|GoogleOther|bingbot|meta-externalagent'

# 1. Every AI agent visit, all statuses
grep -Ei "$AI" access.log

# 2. Volume per agent, busiest first
grep -Eio "$AI" access.log | sort | uniq -c | sort -rn

# 3. Only the error responses served to an agent
grep -Ei "$AI" access.log | awk '$9 ~ /^(403|404|429|500|503)$/'

# 4. Top 20 URLs crawled by GPTBot
grep -i 'GPTBot' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20

# 5. Last recorded visit for one agent
grep -i 'ClaudeBot' access.log | tail -1

# 6. Priority pages never visited, by diffing against the sitemap
grep -Ei "$AI" access.log | awk '{print $7}' | sort -u > seen.txt
comm -23 priority-urls.txt seen.txt

To build the priority page list. llms.txt generator | Hikoo Analyzer

Verification

Why the user agent alone is not proof

A user agent header is a free text string chosen by the client. Anyone can send a request declaring itself GPTBot, and your log will record it as such. A log line is therefore never proof that a vendor visited, it only proves a request claimed that identity. As long as you stay at the level of trend counting, the approximation is acceptable. The moment you decide to block, to charge, or to serve different content, it no longer is.

Two documented methods settle the question. The first is matching the client IP against the ranges the vendor publishes. OpenAI publishes one file per bot, Anthropic publishes a single list, Perplexity publishes one file per crawler. The second is a reverse DNS lookup followed by a forward one, the method Google documents for Googlebot, where the address must resolve to a name under googlebot.com, google.com or googleusercontent.com, and that name must then resolve back to the original address.

A third path is emerging. Web Bot Auth has the bot sign its requests with the Signature, Signature-Input and Signature-Agent headers, built on HTTP Message Signatures from RFC 9421 and on Ed25519 keys. Verification becomes cryptographic and no longer depends on an address list you have to keep current. Cloudflare already implements it for its verified bots, and the matching specifications are still in progress at the IETF, so adoption remains partial today.

Verifying an agent identity
# 1. Reverse DNS on the address found in the log
host 66.249.66.1
# 1.66.249.66.in-addr.arpa domain name pointer crawl-66-249-66-1.googlebot.com.

# 2. Forward DNS on the name returned, it must resolve back
host crawl-66-249-66-1.googlebot.com
# crawl-66-249-66-1.googlebot.com has address 66.249.66.1

# 3. Vendors that publish their ranges in CIDR form
curl -s https://openai.com/gptbot.json
curl -s https://claude.com/crawling/bots.json
curl -sL https://www.perplexity.com/perplexitybot.json
Verification methods published by each vendor, checked on 31 August 2026
VendorPublished methodWhere to find it
OpenAIIP ranges per botopenai.com/gptbot.json, searchbot.json, chatgpt-user.json
AnthropicSingle IP listclaude.com/crawling/bots.json
PerplexityIP ranges per crawlerperplexitybot.json and perplexity-user.json
GoogleReverse then forward DNS, or range filesdevelopers.google.com, crawling/ipranges folder

Google, verifying Googlebot | Cloudflare, Web Bot Auth | IETF, Web Bot Auth architecture

Test

Reproducing an agent visit on your own site

Before you interpret a log file, check that your chain writes what you think it writes. Send a request to your own site with a test user agent, then read back the line it produced. If the user agent is truncated, if the status belongs to an intermediate redirect, or if the request never appears because an upstream cache served it, you find out now rather than halfway through an analysis.

The capture below shows exactly that on a local server. It is a test request we sent ourselves with a user agent string imitating GPTBot, not a visit from an official crawler. Its only purpose is to prove that the log format captures the user agent, the status and the duration, and that errors show up too.

Local test transcript, curl requests with a test user agent and the log lines they produced
Local test run on 31 August 2026. Requests sent by us with a test user agent, this is not a visit from an official crawler. Terminal transcript.
Test request and the resulting log line
# A TEST request to our own local server, sent with a test user agent.
# This is not a visit from an official crawler.

$ UA="Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.4; +https://openai.com/gptbot"
$ curl -s -o /dev/null -w "%{http_code} %{size_download} %{time_total}\n" -A "$UA" \
    http://localhost:3010/fr/blog/guides/logs-serveur-crawlers-ia-guide-2026/
200 460948 0.016284

$ curl -s -o /dev/null -w "%{http_code} %{size_download} %{time_total}\n" -A "$UA" \
    http://localhost:3010/fr/blog/guides/page-qui-nexiste-pas/
404 8376 0.023425

# The two lines actually written to access.log by the combined format + $request_time

$ tail -2 access.log
::1 - - [31/Aug/2026:18:55:31 +0200] "GET /fr/blog/guides/logs-serveur-crawlers-ia-guide-2026/ HTTP/1.1" 200 460948 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.4; +https://openai.com/gptbot" 0.014
::1 - - [31/Aug/2026:18:55:31 +0200] "GET /fr/blog/guides/page-qui-nexiste-pas/ HTTP/1.1" 404 8376 "-" "Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko); compatible; GPTBot/1.4; +https://openai.com/gptbot" 0.020
Diagnosis

Spotting 403, 404, 429, redirects and challenges

The status code is the highest yield field in the file, because it says what the agent actually received. A 200 on an empty page is no better than a 404, and a repeated 403 across a whole section almost always points to a web application firewall rule or an anti-bot protection blocking an agent you believed you were allowing.

The 429 deserves particular attention. RFC 6585 defines it as the response to a client that has sent too many requests in a given amount of time, with an optional Retry-After header telling it how long to wait. Served in volume to a crawler, it slows exploration and delays discovery of your new pages. Anthropic documents support for the non-standard Crawl-delay extension in robots.txt, a cleaner way to pace a crawler than rejecting it with a 429.

Reading HTTP status codes from an AI agent point of view
CodeWhat the agent seesCommon causeAction
200Content servedNormal behaviourCheck the HTML carries the text, not an empty shell
301 or 308Permanent redirectSlash or language normalisationKeep chains down to a single hop
403Access deniedFirewall rule, anti-bot protection, geoblockingAllow the agent at the firewall, not only in robots.txt
404Page missingDead internal link or stale sitemap URLFix the internal links and clean the sitemap
429Too many requestsRate limit set too tightWiden the limit or publish a Crawl-delay
503Service unavailableSaturated origin or maintenanceWatch the correlation with crawl spikes

RFC 6585, status 429 | Anthropic, Crawl-delay

Layers

Nginx, CDN, firewall and host, what each layer sees

A request crosses several layers and each one logs only part of the story. The CDN sees all traffic, including what it serves from cache and what will therefore never reach your origin. The origin server only sees requests that made it through. If you analyse origin logs alone behind an aggressive CDN, you systematically underestimate crawler activity.

On Vercel, runtime logs expose the method, the requested path, the status, the region, the cache state and the request user agent. Two limits matter. First, static requests only appear when they serve cache, and the documentation points to Log Drains to get all static requests. Second, retention is short, one hour on Hobby, one day on Pro, three days on Enterprise, and thirty days with Observability Plus. A thirty day crawl analysis therefore implies an export, not a dashboard lookup.

On Cloudflare, the HTTP requests dataset covers exactly what a crawl analysis needs, notably ClientRequestUserAgent, ClientIP, ClientRequestPath, EdgeResponseStatus, EdgeResponseBytes and EdgeTimeToFirstByteMs. Bot Management customers also get BotScore and VerifiedBotCategory. Cloudflare additionally offers AI Crawl Control, formerly AI Audit, which shows which AI services access your content and works on all plans.

What each layer logs and what escapes it for an AI crawl analysis
LayerWhat it recordsLimit to know
CDN or reverse proxyEvery request, cache hits includedRetention and export often paid features
Web application firewallBlocked requests and challengesA block never reaches the origin log
Origin serverRequests that got past the cacheUnderestimates real crawl volume
Application platformFunctions and middleware, status and user agentPartial static coverage, short retention

Vercel, runtime logs | Cloudflare, HTTP log fields | Cloudflare, AI Crawl Control

Measurement

The minimal dashboard

A useful AI crawl report fits in nine columns. They answer the only questions that matter, namely who comes, where, how often, with what result, and what stays unvisited. Anything beyond that list is comfort, not diagnosis.

Two indicators deserve to be tracked over time rather than read as a single value. Priority page coverage, meaning the share of your strategic URLs fetched at least once in the period, measures your real exposure. The error rate served to agents tends to degrade quietly after a firewall update or a CDN plan change, and a sudden rise almost always explains a drop in visits the following week.

The nine minimal columns of a workable AI crawl report
ColumnLog fieldWhat it is for
Agentnormalised user_agentSeparate search, training and user action
URLrequest lineKnow which pages are actually read
Date and timetime_localSpot spikes and crawl windows
StatusstatusDetect 403, 404, 429 and redirects
Bytesbody_bytes_sentSpot a page served empty or truncated
Latencyrequest_timeSee whether slowness is limiting crawling
FrequencyaggregationVisits per agent per day
Last seenaggregationIdentify pages dropping out
Priority coveragesitemap joinShare of strategic pages never visited
Control

Checking what an agent actually receives

A 200 in the logs does not tell you what was served. A page can respond correctly and still contain only an HTML shell whose text arrives after JavaScript runs, which most AI crawlers do not do. The log gives you the status, the simulator gives you the content.

In the capture below we submitted a public page from our own blog to the Hikoo AI crawler simulator. The result shows the number of words actually readable, the count of headings and links, and the raw text as an agent receives it. Always cross the two, a 200 status in the log and a sane word count in the simulator.

Hikoo AI crawler simulator showing readable word count and the raw text received
Hikoo AI crawler simulator, run on 31 August 2026 against a public page of the Hikoo blog. Source, tryhikoo.com.

Tools used. AI crawler simulator | AI crawler access checker | Free AI audit

Data

Privacy, retention and anonymisation

An access.log contains IP addresses, therefore personal data as soon as human visitors appear in it. A crawl analysis, however, needs no identifying data once identity verification is done. Treat verification and analysis as two separate stages, the first on raw short lived data, the second on an aggregated set you can keep longer.

  • Set an explicit retention period for raw logs and automate the purge, your host default retention is not a policy.
  • Anonymise the IP after verification, for example by truncating the last octet in IPv4 and the trailing segments in IPv6.
  • Keep only the normalised agent, the URL, the timestamp, the status, the bytes and the latency for crawl analysis.
  • Strip query parameters from aggregated URLs, they often carry session or campaign identifiers.
  • Document the purpose and the duration in your processing record, a technical analysis is still processing.
  • Restrict raw log access to people with an operational need, and log those accesses.
Hikoo

Tracking AI agent traffic without a log pipeline

Manual analysis answers a one off question. It holds up badly over time, because you have to collect, deduplicate, verify identities, keep history beyond the platform retention window, and redo the exercise after every infrastructure change.

Hikoo ships AI agent tracking inside the dashboard. It records AI crawler visits to your site, when they come, how often and which pages they read, agent by agent. That view sits alongside Spotlight, which measures how your brand is cited in AI answers. The two answer different questions, one tells you what agents read on your site, the other tells you what they say about you elsewhere.

Putting them together is where the value is. A heavily crawled page that is never cited is a content problem, a page that is never crawled is a technical problem, and only reading both together lets you decide. Hikoo Analyzer completes the picture by scoring how readable each page is for retrieval.

Keep going. Hikoo Spotlight | Hikoo Analyzer | robots.txt and AI crawlers | Prepare your site for AI agents | Measure AI traffic in GA4 | AI visibility

Frequently asked questions

Can I see AI crawlers in Google Analytics instead of the logs?

No. GA4 relies on a JavaScript tag running in a browser, while AI crawlers fetch the HTML without executing that script. GA4 does measure humans arriving from an AI answer, through the referer. The two measurements complement each other and do not replace each other.

How often does an AI crawler come back to a page?

No vendor publishes a guaranteed frequency, and it varies with the site, content freshness and domain authority. Your own logs are the only reliable source on this. Measure the median interval between two visits, per agent and per section, rather than looking for a general rule.

Does a log line with GPTBot prove OpenAI visited?

No. The user agent is declarative and can be spoofed in one command. To settle it, match the client IP against the ranges OpenAI publishes, or use reverse DNS where the vendor documents that method. Without verification, a line only proves that a request claimed that identity.

Why does an agent fetch a page robots.txt disallows?

Because user-triggered agents are not always covered. OpenAI states that robots.txt rules may not apply to actions initiated by a user, and Perplexity notes that Perplexity-User generally ignores robots.txt. Check the exact token before calling it a violation.

What should I do if my logs show many 403s on AI agents?

Find the blocking rule, almost always at the web application firewall or anti-bot layer rather than in robots.txt. Allowing an agent in robots.txt is useless if an upstream layer refuses the connection. Then retest the affected URL with a test user agent to confirm the fix.

How long should I keep logs for this analysis?

Keep raw logs only as long as verification requires, then keep an aggregated, anonymised set for history. On a managed platform, check retention before relying on it, since it can be measured in hours. A scheduled export to storage you control remains the simplest answer.

Should I block training crawlers to protect my content?

That is an editorial call, not a technical rule. Blocking GPTBot or ClaudeBot does not directly affect your presence in search answers, which depends on other tokens. A block also does not erase what has already been crawled. Decide content by content, then measure the effect in your logs.

Conclusion

Server logs remain the only exhaustive measurement of AI agent activity on your site. They tell you which pages are read, how often, with which HTTP status, and which ones stay unvisited, where classic analytics tools see nothing at all. The work comes down to enriching the log format, filtering on the right tokens, verifying identities by IP, then tracking nine columns over time.

The natural next step is to cross that technical reading with your citation data. Start with a free audit of your site to place your readability for agents, then track both crawler visits and brand citations in Hikoo. Putting the two side by side is what tells you what to fix first.

Sources

  1. OpenAI Crawlers and bots, OAI-SearchBot, GPTBot, ChatGPT-User. OpenAI developer documentation, consulted 31 August 2026
  2. Anthropic Does Anthropic crawl data from the web and how can site owners block the crawler. Anthropic support documentation, consulted 31 August 2026
  3. Perplexity PerplexityBot and Perplexity-User. Perplexity documentation, consulted 31 August 2026
  4. Google Verifying Googlebot and other Google crawlers. Google Search Central, consulted 31 August 2026
  5. Google Google user-triggered fetchers. Google crawler documentation, consulted 31 August 2026
  6. nginx Module ngx_http_log_module, log_format and combined. nginx documentation, consulted 31 August 2026
  7. The Apache Software Foundation Log Files, Common and Combined Log Format. Apache HTTP Server 2.4 documentation, consulted 31 August 2026
  8. The Apache Software Foundation mod_log_config, custom log formats. Apache HTTP Server 2.4 documentation, consulted 31 August 2026
  9. Vercel Runtime Logs, fields, filters and retention limits. Vercel documentation, consulted 31 August 2026
  10. Cloudflare HTTP requests log fields. Cloudflare Logs reference, consulted 31 August 2026
  11. Cloudflare AI Crawl Control, formerly AI Audit. Cloudflare documentation, consulted 31 August 2026
  12. Cloudflare Web Bot Auth, cryptographic bot verification. Cloudflare bot solutions documentation, consulted 31 August 2026
  13. T. Meunier HTTP Message Signatures for automated traffic, architecture. IETF Internet-Draft, consulted 31 August 2026
  14. M. Nottingham, R. Fielding, J. Reschke RFC 6585, Additional HTTP Status Codes. IETF, 2012
  15. A. Backman, J. Richer, M. Sporny RFC 9421, HTTP Message Signatures. IETF, 2024
About the author
Timothé Merle
Co-founder Hikoo - Expert AEO/GEO
View LinkedIn profile

Go further

Related Articles

Book a personalized demo

See how Hikoo can boost your visibility on AI search engines.