ChangeGamer

← All guides · The agent-ready web

Measuring AI Agent Traffic: Server-Side Telemetry That Answers Real Questions

Part 10 of The agent-ready web · 1,221 words · published 2026-07-26 · updated 2026-07-26 · Markdown variant

Why client-side analytics miss AI agents entirely, the minimum row schema to log, the five queries worth running, and how to tell a real crawler from a spoofed user agent.

In short

  • Agents mostly do not execute JavaScript, so JS-based analytics record almost none of this traffic. Everything useful is server-side.
  • Six fields are enough: timestamp, path, user agent, status, outcome class, and a bot-verified flag. Resist logging more, especially anything credential-shaped.
  • The decisive metric is the fetch-to-referral ratio per crawler: high fetches with no referrals means you are supplying answers, not receiving visitors.
  • User agents are trivially spoofed. Verify against published vendor IP ranges before you treat a row as a real vendor crawler.
  • Set a decision threshold in advance — "N distinct paywall hits in 30 days" — so that pricing and blocking decisions are made on evidence rather than on the first interesting week.

Part of the The Agent-Ready Website: A Complete Guide to AI Visibility, Access Control and Monetization guide.


You cannot make any of the decisions in the agent-ready website without data, and the data you already have is probably wrong: it comes from a JavaScript tag that agents do not run.

The row schema

Log one row per request that reaches your origin or edge. Six fields carry every insight worth having:

Field Example Why
timestamp 2026-07-26T09:14:03Z Trends, bursts, crawl cadence
path /blog/agent-traffic.md What is actually wanted
user_agent GPTBot/1.2 (truncate to ~100 chars) Which client class
status 200, 403, 402, 429 Whether you served or blocked it
outcome served, blocked, payment_required, upgrade, not_found Business meaning of the status
verified true/false Did the source IP match the vendor's published range

Two rules on what not to log: never record API keys, session identifiers, or tokens — a log store containing credentials is a credential store — and keep user agents truncated so a hostile client cannot inflate your storage with a megabyte UA.

If you run at an edge platform, this is a handful of lines in the request path. This site writes exactly this shape into a Cloudflare Analytics Engine dataset from its Worker; the same pattern works with any log sink you can query.

function logAccess(env, req, res, outcome) {
  const ua = (req.headers.get("user-agent") ?? "").slice(0, 100);
  env.ANALYTICS.writeDataPoint({
    indexes: [new URL(req.url).pathname],
    blobs: [classOf(ua), outcome, ua, res.status.toString()],
    doubles: [1],
  });
}

One caveat worth designing around: requests served straight from a CDN cache or static-asset layer may never reach your logging code. Decide deliberately which surfaces are counted, and write it down — otherwise you will later read a zero as "no demand" when it means "not instrumented". Index files such as /llms.txt and robots.txt are commonly in this category.

The five queries that drive decisions

1. Who is visiting, and are they real?

SELECT user_agent, COUNT(*) AS n, SUM(verified) AS verified_n
FROM access_log WHERE timestamp > now() - interval 30 day
GROUP BY user_agent ORDER BY n DESC LIMIT 25

Look for the tokens that matter: training crawlers, answer-engine indexers, live user fetchers. A large gap between n and verified_n for a vendor token means somebody is spoofing it — usually a scraper hoping you allowlisted that name. The token reference is AI crawler policy.

2. Am I accidentally blocking the crawlers I want?

SELECT user_agent, status, COUNT(*) AS n
FROM access_log WHERE timestamp > now() - interval 7 day
  AND status IN (403, 429, 503)
GROUP BY user_agent, status ORDER BY n DESC

This is the query that pays for the whole setup. A wall of 403s against a crawler your robots.txt allows means bot management or a browser-integrity check is overriding your published policy — the exact failure this site hit, where a managed rule silently 403'd six named AI crawlers including on / and /sitemap.xml. Everything in that family is catalogued in why AI agents can't read your site.

3. What do they actually want?

SELECT path, COUNT(*) AS n, COUNT(DISTINCT user_agent) AS clients
FROM access_log WHERE outcome = 'served' AND timestamp > now() - interval 30 day
GROUP BY path ORDER BY n DESC LIMIT 30

Read the distribution, not the top row. Concentrated demand on a few URLs means those pages are a product; flat demand across everything means your corpus is the product. That distinction decides your entire pricing shape — see what to charge AI crawlers.

4. Does the traffic come back as visitors?

-- referrals from answer-engine domains, from the same log
SELECT referer_host, COUNT(*) AS visits
FROM access_log WHERE timestamp > now() - interval 30 day
  AND referer_host IS NOT NULL
GROUP BY referer_host ORDER BY visits DESC LIMIT 20

Then compute the ratio that matters: fetches by answer-engine crawlers ÷ referrals from that engine's domain. A high ratio means your content is being consumed to produce answers that do not send anyone your way. That is not necessarily bad — brand presence in answers has value — but it is the number that turns "should we monetize or restrict this?" from a philosophical question into an arithmetic one.

5. If you gate anything, does the wall convert?

SELECT outcome, COUNT(*) AS n
FROM access_log WHERE timestamp > now() - interval 30 day
  AND outcome IN ('payment_required', 'upgrade', 'served_paid')
GROUP BY outcome

A funnel with many payment_required rows and no paid fetches means the price is wrong, the payment path has friction, or the buyers were never commercial. upgrade rows — valid keys of insufficient tier — are the cleanest upsell signal that exists, because someone already paid you once.

Verifying crawlers: three options

Method Effort Strength
UA string match Trivial None — trivially spoofed
Reverse DNS + forward confirmation Low Good for vendors that support it
Vendor published IP ranges Moderate (refresh periodically) Strong, and what vendors recommend
Signed requests (cryptographic bot auth) Depends on adoption Strongest; removes IP lists entirely

The last row is where this is heading: instead of maintaining allowlists of addresses, the client proves its identity by signing the request. The state of that work is covered in web bot auth. Until it is universal, IP-range verification is the practical answer, and it belongs in your logging path so verified is a field rather than a later investigation.

Decide in advance what would change your mind

The most common analytical failure here is not a missing metric, it is acting on a week of noise. Write the thresholds down before you look:

A pre-committed threshold converts an argument into a measurement.

A one-screen dashboard

Four panels, refreshed weekly, are enough to run this:

  1. Requests per crawler per week, stacked by status. Catches blocking and bursts.
  2. Top 20 paths by served requests. Shows what your product actually is.
  3. Fetch-to-referral ratio per answer engine. The strategic number.
  4. Outcome funnel (servedpayment_requiredserved_paid). Only if you gate anything.

If you also run agents of your own — and most sites building anything with LLMs now do — the tracing discipline on that side is a different problem with a mature toolset, covered in agent observability and tracing.

Privacy, briefly

This is machine traffic, but the same log can carry human requests, so apply the usual discipline: no credentials, truncate user agents, avoid full query strings where they can carry personal data, keep retention short and documented, and aggregate rather than hoard. Nothing in this guide requires identifying a person, and a schema that cannot identify one is a schema you never have to defend.

Frequently asked questions

Why does Google Analytics not show AI crawler traffic?
Because it is a client-side tag: it needs JavaScript to execute in order to record a hit. Most crawlers and many agents never run it. Whatever your JS analytics shows for AI bots, treat it as a lower bound that is close to zero rather than as data.
How do I know a request claiming to be GPTBot really is?
Check the source IP against the vendor's published ranges — every major vendor publishes them. UA strings are a claim, not evidence. An emerging alternative is cryptographic bot authentication, where the client signs its requests, which removes the need for IP lists entirely.
How long should I keep this data?
30 to 90 days is enough for every decision in this cluster and keeps the storage question boring. Aggregate older data into monthly counts rather than retaining raw rows.
What is the single most useful chart?
Requests per crawler per week, split by HTTP status. It surfaces the two failures that matter — an edge rule blocking crawlers you meant to allow, and a crawler hammering a path you did not expect — long before anything else does.

#analytics #observability #crawlers #measurement #ai-visibility

Agents: this guide is available as Markdown and JSON; the whole cluster is indexed at /api/articles.json. The reference corpus behind it is at /llms.txt, with licensing at pricing.