MarketingPlaybook16 min readPublished August 6, 2026

A crawler never fires your tag · 81.7% of AI-bot requests are training-oriented · 3.2% have a human waiting · rolling window

Server Logs: Finding the AI Agents That GA4 Can’t See

Analytics platforms measure people who arrived because an assistant cited you. They cannot measure the layer underneath — autonomous crawlers and user-triggered fetches that never execute a line of JavaScript. That layer exists only in your server logs, and reading it takes a different toolchain, a different vocabulary and a different set of honest limits.

DA
Digital Applied Team
Senior strategists · Published Aug 6, 2026
PublishedAugust 6, 2026
Read time16 min
SourcesVendor crawler docs + Cloudflare Radar
Training-oriented crawls
81.7%
training plus training-and-search, combined, rolling window
Live user-action fetches
3.2%
the only slice with a person on the other end, rolling window
Documented OpenAI agents
4
four documented agents, four different downstream roles
Top-five bot share
70.3%
of AI and crawl bot HTTP requests, rolling window

Server log AI agent detection is the measurement layer sitting underneath everything your analytics platform reports. A JavaScript-based tag only fires when a browser executes it. An autonomous crawler issues an HTTP request, receives your HTML and leaves — no script execution, no session, no event. The request is real, it consumed your bandwidth and it may have shaped an answer about your brand, but the only place it exists is your access log.

That gap matters more every quarter. The vendors building answer engines now run separate agents for separate jobs — training-corpus collection, search-index building, live user-triggered fetches — and each one carries a different consequence when you block it. Treating them as a single bucket called “AI traffic” hides the decision you actually care about, and no client-side analytics product is positioned to tell them apart.

This playbook covers the structural reason the tag never fires, the crawl-purpose split running through the vendor documentation, a cross-vendor user-agent reference matrix, why a UA string is a claim rather than an identity, what the current traffic mix actually looks like, a six-step log-analysis recipe, and an honest limits section about the one number nobody can give you. For the analytics side of the same problem — how assistant-referred human sessions get classified — see our GA4 AI Assistant channel playbook, which owns that half and is not repeated here.

Key takeaways
  1. 01
    Client-side analytics is structurally blind to agents.A crawler does not execute JavaScript, so no tag fires and no session is created. This is a property of how measurement works, not a configuration gap you can close with a channel group.
  2. 02
    OpenAI and Perplexity ship the same three-way split.Both separate training-corpus collection from search-index building from live user-triggered fetch. Neither vendor frames this as a pattern; assembling it across both does.
  3. 03
    Blocking GPTBot does not remove you from ChatGPT search.That control belongs to OAI-SearchBot, and the two settings are independent. A blanket block-all-AI-bots rule quietly forfeits citation visibility while doing nothing you intended.
  4. 04
    A user-agent string is spoofable; an IP range is not.OpenAI and Perplexity both publish machine-readable IP-range files precisely so log analysis can verify the claim. There is no equivalent verification step available to a client-side tag.
  5. 05
    Most agent traffic is still corpus-building, not answering.In the current rolling window, training and training-and-search purposes together account for 81.7% of AI-bot HTTP requests, while live user-action fetches account for 3.2%.

01The Blind SpotTwo data sources, two different questions.

Start with the mechanism rather than the dashboard. A client-side analytics platform works because a browser downloads your page, runs a script, and that script posts an event to a collection endpoint. Everything downstream — sessions, channels, attribution, conversion paths — is built on that one event having happened.

An autonomous crawler does none of that. It opens a connection, sends a request with a user-agent header, takes the HTML body, and disconnects. There is no script execution and therefore no event, no session and no channel assignment. The interaction is invisible to the analytics product not because the product is misconfigured but because the product was never in the request path.

The consequence is worth stating plainly, because a lot of published advice implies otherwise: you cannot fix agent measurement by adding a custom channel group, a regex on referrer, or a new dimension. Those tools operate on events that exist. Agent requests produce no events. The only artefact they produce is a line in an access log, which is why this is a server-side discipline and sits closer to server-side tracking methodology than to anything in a tag manager.

Structural, not a configuration gap
If a request never executes your JavaScript, no amount of analytics configuration will surface it. The fix is not a better channel definition — it is a second data source that sees requests rather than sessions. Run both; they answer different questions and neither replaces the other.

02Crawl PurposeOpenAI and Perplexity ship the same purpose split.

Read OpenAI and Perplexity’s crawler documentation side by side and a pattern emerges that neither of them describes as a pattern, because each is only documenting itself. Both separate the job of collecting training data from the job of building a search index from the job of fetching one page because a live user asked a question. The names differ. The taxonomy does not. OpenAI carries a fourth agent on top of those three for ad-page safety, which is why the grid below runs to four cards rather than three; Google’s documented controls, covered in the matrix that follows, do not include a user-fetch agent at all.

This is the single most useful thing to internalise before you touch a log file, because the purpose determines what a block actually costs you. Blocking a training crawler removes your content from a corpus. Blocking an index crawler removes you from an answer engine’s citations. Those are different business outcomes with different reversibility, and collapsing them into one row in a report makes the trade-off impossible to see.

Purpose 01
Training crawl
GPTBot/1.4 · Google-Extended (robots token)

Unattended collection for model training. GPTBot is a real crawler that issues its own requests and appears in your log as its own user agent. Google-Extended is different in kind: it is a robots.txt token controlling whether crawled content trains future Gemini models and is used for grounding in Gemini Apps and Vertex AI, and it rides existing Googlebot fetches rather than issuing requests of its own.

No human waiting
Purpose 02
Search index
OAI-SearchBot/1.4 · PerplexityBot/1.0

Builds the answer engine’s retrievable index. Perplexity states directly that PerplexityBot is not used to crawl content for AI foundation models — the index and the training corpus are separate systems with separate controls. This is the category whose blocking decision costs you citation supply.

Citation supply
Purpose 03
User fetch
ChatGPT-User/1.0 · Perplexity-User/1.0

A person asked a question and the assistant fetched your page to answer it. OpenAI documents ChatGPT-User as not used for crawling the web in an automatic fashion, and Perplexity describes Perplexity-User as a live page fetch triggered by a specific user question. This is the only category with someone waiting on the other end, which is why it belongs in a traffic model rather than a bot report.

Human in the loop
Purpose 04
Ads safety
OAI-AdsBot/1.0

Validates advertising page safety rather than collecting a corpus or building an index. Low volume and easy to misfile as a training crawl if your classifier matches on the vendor rather than the specific agent, which is exactly the error that makes an AI-traffic report look bigger and less actionable than it is.

Compliance check
The expensive misconception
Disallowing GPTBot in robots.txt does not remove a site from ChatGPT’s search results — that control belongs to OAI-SearchBot, and the two settings are independent. A blanket “block all AI bots” rule therefore forfeits citation visibility as a side effect of a training-data decision. If you want the economics of that choice rather than the mechanics, our AI crawl economics breakdown runs the numbers.

03Reference MatrixThe AI agent user-agent matrix.

Each vendor publishes its own agent list. Nobody publishes the cross-vendor version with the two columns that actually drive decisions: whether robots.txt is a documented control for that agent, and what blocking it does not affect. The table below assembles that from the OpenAI, Perplexity and Google primary documentation as it read at the time of writing.

Two rows carry an explicit gap. Anthropic’s crawler documentation was unreachable when this was compiled, and no Meta primary was available for Meta-ExternalAgent, so their exact user-agent strings are deliberately absent rather than guessed. Both agents are nevertheless significant by volume, so they appear with what is actually verifiable — their share of requests — and nothing more.

Cross-vendor AI agent reference matrix assembled from OpenAI, Perplexity and Google primary crawler documentation, grouped by vendor, listing each agent’s exact user-agent token, declared purpose, whether robots.txt is a documented control, the published IP-verification endpoint, and what blocking that agent does not affect — except in the final group, where no vendor primary was available and the last column instead holds that agent’s verifiable share of requests.
AgentExact tokenDeclared purposeRobots.txt controlIP verification fileWhat blocking it does NOT affect
OpenAI — four agents, four downstream roles
GPTBotGPTBot/1.4Training-data collectionYes — the documented opt-out for trainingopenai.com/gptbot.jsonYour presence in ChatGPT search results — that is a separate agent
OAI-SearchBotOAI-SearchBot/1.4ChatGPT search indexYes — the control for search inclusionopenai.com/searchbot.jsonModel training collection — that remains a GPTBot decision
ChatGPT-UserChatGPT-User/1.0User-initiated fetch; documented as not used for crawling the web in an automatic fashionNot documented in the sources checkedopenai.com/chatgpt-user.jsonTraining corpus and search index, both governed separately
OAI-AdsBotOAI-AdsBot/1.0Validates ad-page safetyNot documented in the sources checkedopenai.com/adsbot.jsonOrganic citation or training paths — different agents entirely
Perplexity — index versus live user question
PerplexityBotPerplexityBot/1.0Builds the search index; stated as not used to crawl content for AI foundation modelsYes — the crawl-purpose agent, contrasted against Perplexity-Userperplexity.com/perplexitybot.jsonLive user-triggered fetches, which follow a different governance model
Perplexity-UserPerplexity-User/1.0Live page fetch triggered by a specific user questionNo — generally ignores robots.txt, because a user rather than a crawl scheduler triggered the requestperplexity.com/perplexity-user.jsonIndex inclusion, which is the PerplexityBot decision
Google — a token, not only a crawler
Google-ExtendedGoogle-ExtendedControls whether crawled content trains future Gemini models and is used for grounding in Gemini Apps and Vertex AIIt is the robots.txt token; it issues no requests of its ownNone published — nothing to verify, since it rides Googlebot fetchesGoogle states it does not impact inclusion in Google Search nor act as a ranking signal
Google-CloudVertexBotGoogle-CloudVertexBotSite-owner-requested crawl for building Vertex AI AgentsNot documented in the sources checkedNot published in the sources checkedSearch crawling and Gemini training, which are separate decisions
Present in the traffic data — user-agent strings not verified from a vendor primary at the time of writing
ClaudeBotNot verified — do not hard-code a string you have not read in the vendor docsNot sourced from a vendor primaryNot sourcedNot sourcedVerifiable at the time of writing: 14% of AI and crawl bot HTTP requests in the rolling window
Meta-ExternalAgentNot verified — no vendor primary was available this passNot sourced from a vendor primaryNot sourcedNot sourcedVerifiable at the time of writing: 14.4% of AI and crawl bot HTTP requests, ahead of GPTBot

Two structural observations fall out of the matrix once it is assembled. First, the “what blocking does not affect” column is almost always populated — which means almost every blocking decision people describe as one decision is really two or three independent ones. Second, the one agent that explicitly does not honour robots.txt is the one representing a live human request, which inverts the usual intuition that the more autonomous something is, the less it respects your rules.

04VerificationA user-agent string is a claim, not an identity.

Anyone can send a request announcing itself as GPTBot. The header is free text, set by the client, and there is nothing in the protocol that makes it true. Any report built purely on string matching is therefore counting assertions, not agents — and it will overcount in exactly the direction that flatters the report.

Both vendors examined here solve this the same way: they publish a machine-readable file of the IP ranges their agents actually fetch from. OpenAI publishes one per agent, and Perplexity does the same. The verification step is mechanical — match the user-agent token, then confirm the source address falls inside the published range, and only then increment the counter.

Verification endpoints
Published IP-range files
6

Four from OpenAI covering GPTBot, OAI-SearchBot, ChatGPT-User and OAI-AdsBot, plus two from Perplexity covering PerplexityBot and Perplexity-User. Cache them locally, refresh on a schedule, and treat an unverified match as a separate bucket rather than dropping it silently.

openai.com · perplexity.com
Client-side equivalent
IP checks available to a tag
0

A JavaScript tag cannot verify the origin of a request it never received. Verification is a server-side capability by construction — which is the cleanest argument that log analysis complements client-side analytics rather than duplicating it.

Structural, not a gap
Purpose confusion
Distinct agents from one vendor
4

OpenAI alone runs four, each with a different downstream consequence. Matching on the vendor name, or on a loose substring, collapses them into a single number and destroys the only distinction your blocking policy actually depends on.

Match the agent, not the vendor
A user-agent header is the only part of a request the client gets to write about itself. Treat it as testimony, then go and check the address it came from.— Digital Applied, editorial synthesis

05Traffic ShareMost agent traffic is still corpus-building.

Cloudflare Radar publishes a live view of AI and crawl bot activity across its network, including a breakdown by the crawl purpose each bot declares. The two charts below are a snapshot of its rolling seven-day window at the time of writing. That framing matters: this is a dashboard that moves, not a fixed historical statistic, so re-pull it before quoting rather than treating these figures as durable.

Top five AI and crawl bots by share of HTTP requests

Source: Cloudflare Radar AI Insights · live rolling seven-day window, snapshot taken at the time of writing
GooglebotGeneral search crawl
24.4%
Meta-ExternalAgentSecond by volume, ahead of GPTBot
14.4%
ClaudeBotAnthropic
14%
GPTBotOpenAI training-data collection
8.9%
BingbotGeneral search crawl
8.6%

Declared crawl purpose · share of AI-bot HTTP requests

Source: Cloudflare Radar AI Insights · live rolling seven-day window, snapshot taken at the time of writing
TrainingCorpus collection only
42.3%
Training & SearchDual-purpose fetches
39.4%
SearchIndex building only
14%
User actionA person is waiting on this one
3.2%
UndeclaredNo purpose declared
1.1%

Run the arithmetic and the popular narrative inverts. Training and training-and-search together account for 81.7% of AI-bot requests in this window, while the live user-action category — the fetches where a person is genuinely waiting for an answer that includes your page — accounts for 3.2%. That is roughly twenty-five training-oriented requests for every one request with a human attached. Most agent traffic is not answering a question about you; it is reading you into a model.

The bot ranking carries a second correction. Meta-ExternalAgent sits at 14.4% against GPTBot’s 8.9% — about 1.6 times the volume — yet it is largely absent from AI-traffic coverage, which skews heavily toward OpenAI, Perplexity and Anthropic. If your classifier only knows the agents you have read about, your report will be wrong by roughly the size of the agent you have not. For the wider longitudinal picture, our AI crawler and bot traffic statistics reference tracks these series over time.

Our read on where this goes: the user-action slice is the one to watch, not the headline total. As assistants shift from answering out of a pre-built index toward fetching pages live at question time, that 3.2% is the series that should grow, and it is the only series whose growth plausibly correlates with commercial outcomes. A total that swells because a new lab started a training crawl tells you about someone else’s roadmap. A rising user-action count tells you people are asking questions your pages answer.

The markdown shortcut is smaller than it sounds
In the same dataset, HTML accounts for 71.1% of responses served to AI bots, with markdown under 0.1%. The obvious optimisation is to serve agents something lighter — but Cloudflare’s own Markdown-for-Agents data shows a median response-size reduction of only 7.1%. Worth doing for other reasons; not the bandwidth win the narrative implies.

06Log RecipeSix steps from a raw access log to a number you can defend.

None of this requires a vendor. It requires access to your own request data and the discipline to run the same pipeline every month so the series is comparable with itself.

1. Get a log that actually contains the requests

You need timestamp, request path, HTTP status, user-agent and client IP at minimum. Take it from your CDN or edge layer rather than the origin where possible — anything served from edge cache may never reach an origin log, which silently undercounts exactly the high-frequency crawlers you most want to see.

2. Classify by agent, never by vendor

Exact-match the published tokens from the matrix above. Resist the substring shortcut: a rule matching on a vendor name folds four OpenAI agents with four different consequences into one meaningless row, and a rule matching on the word “bot” will sweep in every uptime monitor you run.

3. Verify before you count

For every matched request, check the source address against the vendor’s published IP-range file. Keep unverified matches in their own bucket rather than discarding them — a rising unverified count is itself a signal, either that a range file changed or that something is impersonating a crawler.

4. Report purpose as separate series

Training, search-index, user-fetch and ads-safety go in four different lines on the chart. Never sum them into a single “AI traffic” figure. They move for different reasons, they respond to different controls, and averaging them produces a number that cannot drive any decision.

5. Join the log to your content map

Which URLs are being fetched, how deeply, how often, and what status codes they receive. A 404 or an unnecessary redirect served to an index crawler is a citation you quietly lost, and it is only visible here — the analytics side has no record of a request that never became a session. If citation volume is the outcome you care about, pair this with our analysis of AI search citation behaviour on top-ranking pages.

6. Reconcile against the analytics side

The user-fetch series is the only one that should correlate with assistant-referred sessions; the training and index series should not. OpenAI states that ChatGPT automatically includes the UTM parameter utm_source=chatgpt.com in referral URLs, which gives you a clean join key on the analytics side without any custom tagging — see our UTM tagging fundamentals if that layer is not already clean. Building this reconciliation into a monthly reporting rhythm is standard scope in our analytics engagements.

Three ways this pipeline quietly lies to you
Sampled logs make small agents disappear entirely. Bot-filtering middleware can drop the rows before your pipeline ever reads them. Edge caching can serve an agent without the origin recording anything. Confirm all three before you trust a downward trend — falling agent traffic and a changed logging configuration look identical in a chart.

07The SeamLogs plus analytics — not instead of.

The two systems are complements with a narrow, valuable overlap. The analytics side answers how many people arrived because an assistant surfaced you, and what those people did once they landed. The log side answers which agents fetched what, for which declared purpose, and whether you served them correctly. Neither can answer the other’s question, and a report that pretends otherwise is the most common failure mode in this space. Both feed the same downstream decision, which is why we treat log-side agent data as an input to agentic SEO programmes rather than as a separate infrastructure report.

We are not going to re-explain channel configuration here, because that is a solved problem with its own home: our GA4 AI Assistant channel playbook owns the analytics-side setup, the referrer-classification gaps and the dark-traffic framing in full. Read it as the companion piece; everything on this page assumes it and adds the layer beneath it.

One mechanical detail is worth carrying across the seam, because it shows where the classification actually comes from. Default channel assignment works on exact matches — a session lands in the AI Assistant channel when its medium exactly matches ai-assistant, and lands in Direct only when the source is exactly (direct) and the medium is (none) or (not set). Google documents the automatic path as applying when the referrer matches its list of AI assistants — a list you neither own nor see. That is the structural argument for keeping a log-side series that does not depend on anyone else’s classification decisions.

Assistant-referred humans
Sessions that carry a referrer

A person clicked a citation and arrived in a browser that ran your tag. This is a client-side measurement problem end to end — channel definitions, UTM hygiene, engagement metrics. Server logs add nothing here that analytics does not already do better.

Analytics side
Autonomous crawls
Training and index fetches

No browser, no tag, no session. Adding the training, training-and-search and search-only purposes together, these account for 95.7% of AI-bot requests in the current window — everything except live user actions and undeclared traffic. They exist exclusively as log lines, and no analytics configuration surfaces them, so do not spend a sprint looking for one.

Server logs only
User-triggered fetches
ChatGPT-User and Perplexity-User

The one series that appears on both sides at different moments: the fetch lands in your log, and the click — if it happens — lands in analytics. Joining them gives you a fetch-to-visit ratio you cannot obtain from either source alone, and it is the closest thing to an AI-visibility conversion rate available today.

Both, joined
Blocking decisions
Policy, then economics

Start from the log so you know which agents are actually present and at what volume, then price the trade-off rather than applying a blanket rule. The purpose split is what makes this tractable: training and citation supply are independently controllable.

Logs first, economics second

08Honest LimitsWhat nobody can honestly tell you yet.

The question every stakeholder asks first is what share of AI traffic is invisible. There is no defensible single answer, and the reason is more interesting than the missing number. Published figures do not disagree about one quantity — they measure three different quantities and present all three as if they were the same statistic.

Three circulating dark-traffic figures compared by what each one actually measures, its denominator, its source type, and why the three cannot be reconciled, averaged or ranked against one another.
Figure as circulatedWhat it measuresSource typeWhy it cannot be compared with the others
Three published figures — three different denominators
1.08% is AI referralAI-referred sessions divided by all web traffic in one tracker’s panelgrowth-onomics.com, a third-party tracker; methodology and panel not disclosedThe denominator is the entire web, so the figure is small by construction and says nothing about invisibility
12–18% is AI referralAI-referred sessions divided by referral traffic onlyupgrowth.in and theworlddata.com, different third-party trackers; also non-primaryThe denominator excludes direct, organic and paid entirely — a far smaller base, so a far larger percentage
Roughly 60–70% arrives darkAI traffic with no referrer divided by AI traffic itselfOur own prior estimate in the companion post — not an external primaryMeasures invisibility inside AI traffic rather than AI traffic’s size; cannot be averaged with either row above

The gap between the smallest and largest circulating figure is more than tenfold, but that spread is not evidence of a disagreement about one number. It is evidence that no one has settled which number is being asked about. None of the three is a primary source with a disclosed panel and a stated denominator, which is why this page prints all three with their denominators attached and refuses to reduce them to one.

The structural argument does not need a percentage anyway, and it holds regardless of which tracker turns out to be closest. A request that never executes JavaScript cannot reach a client-side tag. A request arriving with no referrer header cannot be attributed by referrer. Both statements are true of your site today, and your own logs will give you your own figure for your own domain — the only number that should drive a decision about your own budget.

Do not print a single dark-traffic percentage
If a report hands you one number for how much AI traffic is invisible, ask what the denominator was. In our experience the answer is usually absent, and when it is present it rarely matches the denominator of the figure it is being compared against. Measure your logs, monthly, the same way each time.

09ConclusionThe measurement layer under the measurement layer.

Where this leaves a measurement plan, August 2026

Your analytics tells you who arrived. Your logs tell you who came looking.

The agent layer is not a rounding error on a marketing report; on the current mix it is the majority of the machine traffic reaching your pages, and it is entirely absent from the surface most teams use to make decisions. Client-side analytics was never designed to see it, and there is no configuration that changes that. The work is to add a second data source — one that reads requests rather than sessions — and to report it as its own series rather than folding it into a total.

Get the vocabulary right and most of the confusion dissolves. There is a training crawl, a search-index crawl, and a live fetch on behalf of a person asking a question, and both OpenAI and Perplexity ship all three. Those are three different business relationships with three different blocking consequences, and the moment a report calls them one thing, the decision it exists to support becomes impossible to make.

Where this heads next is reasonably legible. The user-action slice is small today, and it is the slice that grows if assistants keep shifting toward live retrieval at question time. Teams that start counting it now — with agents matched exactly, source addresses verified, and purposes reported separately — will have a baseline when it matters. Teams waiting for an industry benchmark to tell them what normal looks like will be waiting a while, because the three figures currently circulating are not even measuring the same thing.

See the traffic your analytics cannot

Most of the machine traffic reaching your site is invisible by default.

We build the server-log and analytics pipeline together — agents matched exactly, source addresses verified against vendor IP ranges, crawl purposes reported as separate series, and the whole thing reconciled against your assistant-referred sessions every month.

Free consultationExpert guidanceTailored solutions
What we work on

AI and agent measurement builds

  • Server-log agent classification with IP verification
  • Crawl-purpose reporting as separate, comparable series
  • Log-to-analytics reconciliation on user-triggered fetches
  • Crawler access policy priced against citation supply
  • Monthly reporting rhythm that survives a taxonomy change
FAQ · Server-log AI agent detection

The questions we get every week.

Because a crawler never runs the code that reports to it. Client-side analytics works by having a browser download your page, execute a JavaScript tag, and post an event to a collection endpoint. An autonomous crawler opens a connection, sends a request, takes the HTML and disconnects — no script execution, no event, no session, no channel assignment. This is a property of how the measurement works rather than a misconfiguration, which is why no custom channel group, referrer regex or extra dimension will surface it. The only artefact an agent request leaves behind is a line in your server or CDN access log, so agent measurement is a server-side discipline. The analytics platform is still the right tool for the other half of the problem: people who clicked an assistant’s citation and arrived in a real browser.
Related dispatches

Continue exploring AI measurement.