TIME serves bots a different website, and User-Agent is now a billing identity
TIME forks its content per crawler and logs each bot read as a billable ad impression. The routing key for that whole ledger is a header any client can type.
Someone fetched the same TIME health article over and over from one machine, changing exactly one thing between requests: the User-Agent header. As Chrome, the response was 200 OK, text/html, and 303,235 bytes. Safari got the same 303KB. So did Googlebot. As ClaudeBot, the same URL in the same second came back as text/markdown at 13,409 bytes, and PerplexityBot and OpenAI's OAI-SearchBot got that markdown byte for byte.
Two different products at one URL, and the switch is a string the client picks for itself.

The switch is a string, and the string is the invoice
The content fork is what made Hacker News. The response headers are the part that should bother anyone who runs an origin:
content-type: text/markdown; charset=utf-8
cache-control: no-store
x-mobian-registry-version: 2026-07-28.v9
x-mobian-impression: 46dfff3c-fb40-41cc-85e1-8b1fa637083a
x-mobian-tokens: 3323
x-mobian-format: mdx-mobian-impression is a fresh UUID on every single request; fetch the same page twice and you get two different IDs. Paired with cache-control: no-store, every bot read gets logged as a distinct ad impression, and x-mobian-tokens: 3323 names the unit being counted. Kin Lane found the same UUID rotation on the ad block itself, delimited in the markdown by a <!-- mobian-agent-ad ... campaign="ally-2026-q3" --> comment, and called it what it is: a per-impression token, the billing and measurement primitive.
None of this is a side experiment. TIME converted its pages to markdown in July 2026 with the ad tech platform Mobian, sells one agent ad per markdown page, charges a premium for it, and counts Ally Bank and the Project Management Institute among its first buyers. Both companies call it the first time a publisher has served ads aimed specifically at AI agents. Mobian CEO Jonah Goodhart's pitch is that the agent is the better target: "Maybe it's more important to influence the agent than even the human, because with a human you influence one person. When you influence ChatGPT, you're influencing potentially all of ChatGPT."
So there is now an ad ledger whose primary key is User-Agent. That's a different kind of dependency than the one bot identification used to carry. Getting crawler detection wrong used to mean skewed analytics. Getting it wrong now means an advertiser paid for impressions a script generated, or that the cheap tier, 13,409 bytes against 303,235, goes to whoever asks for it in the right voice.
The edge already doesn't trust the header
The best evidence that User-Agent can't hold this job comes from the audit itself.
Lane's first pass, run entirely with curl, showed GPTBot, ChatGPT-User, and Claude-User refused with a 406, and his first read was that TIME was blocking those three outright. Then he ran the identical user-agent strings through Python and got 200, markdown, and ads for all three. Nothing in the headers explained the difference. He attributes it to TLS fingerprinting scored by Fastly's bot management: the edge is grading the handshake, so a scripted client that declares itself a bot gets refused while the same client wearing a Chrome user-agent sails through.
Read that as an admission. The edge isn't making a decision on User-Agent. It's making a decision on User-Agent plus a heuristic guess about the TLS stack, because the header alone is worthless as evidence. Cloudflare says the same thing in plainer terms: user agent headers alone are easily spoofed and insufficient for reliable identification, and IP range validation is brittle because ranges are shared between services and change over time. RFC 9110 doesn't even treat masquerading as an error. It says that if a user agent masquerades as a different user agent, recipients can assume the user intentionally wants the responses tailored for that identity.
The heuristics are also load-bearing in the other direction. TIME's own llms.txt allows OpenAI, Perplexity, Scale, and ElevenLabs and disallows everyone else, while every Anthropic agent is being served markdown and ads. Stated policy and deployed behavior disagree, and the only way anyone found out was by impersonating crawlers and diffing the results.
Meanwhile the population of clients that lie is growing. A stealth crawler presents itself as an ordinary Chrome browser or comes in over a residential IP. Human Security measured AI scraper traffic growing 597% from January to December 2025, with scraping attacks touching nearly 20% of site traffic for the median organization. People Inc. went from blocking roughly 2,100 user agents to over 30,000 when it moved to a block-all posture. That's what a denylist keyed on self-declared strings looks like at scale: 30,000 entries and still guessing.
What a verifiable claim looks like
Web Bot Auth is the version of this that produces evidence instead of a guess. It rests on two IETF drafts, a directory draft that lets a crawler publish its public keys, and a protocol draft defining how those keys attach identity to a request, and it's built on RFC 9421 HTTP Message Signatures, which Cloudflare is prioritizing over its request-mTLS alternative because RFC 9421 is already adopted, has reference implementations, and works at the HTTP layer.
The operator side starts with a key:
openssl genpkey -algorithm ed25519 -out private-key.pemThat public key goes into a JSON Web Key Set hosted at /.well-known/http-message-signatures-directory over HTTPS, and the directory response itself must be signed so nobody can mirror it and register on your behalf. Every outbound request then carries three headers. Cloudflare's documented example:
Signature-Agent: "https://signature-agent.test"
Signature-Input: sig2=("@authority" "signature-agent")
;created=1735689600
;keyid="poqkLGiymh_W0uP6PZFw-dvez3QJT5SolqXBCW38r0U"
;alg="ed25519"
;expires=1735693200
;nonce="e8N7S2MFd/qrd6T2R3tdfAuuANngKI7LFtKYI/vowzk4lAZYadIX6wW25MwG7DCT9RUKAJ0qVkU0mEeLElW1qg=="
;tag="web-bot-auth"
Signature: sig2=:jdq0SqOwHdyHr9+r5jw3iYZH6aNGKijYp/EstF4RQTQdi5N5YYKrD+mCT1HA1nZDsi6nJKuHxUi/5Syp3rLWBA==:keyid is the JWK thumbprint, tag declares the signature's purpose, and expires should be short. Cloudflare recommends short-lived intervals specifically to limit replay. Replay matters more than usual when the request is an impression: a signature with a generous validity window is a coupon for duplicate billing.
This part already runs in production. Cloudflare's signed agents classification covers agents directed by an end user whose infrastructure signs requests via Web Bot Auth, with a first cohort of ChatGPT agent, Goose from Block, Browserbase, and Anchor Browser. For the case where the operator isn't the party you're actually pricing, Cloudflare calls the website → operator → end user chain transitive trust, and is experimenting with the RFC 7239 Forwarded header to carry the operator and its content-use commitment:
Forwarded: for="openai";use="reference"An identity claim plus a declared purpose, on the request, verifiable. That's the shape a metered content tier actually needs.
The cost of this lands on the bot operator, and it's real. You now own a signing key, a JWKS endpoint that has to stay up and stay signed, and a rotation story nobody wants to be on call for. A leaked key is worse than a spoofed header, because it turns a forgery into an authenticated request the verifier will cheerfully bill. Short expires windows shrink the blast radius. They don't change the fact that the key is now a production credential.
Signatures don't fix the parts that aren't about identity
The honest objection is that none of this makes TIME's product good.
A signed agent can still be a bad customer. Cryptography tells you who sent the request. It says nothing about what that requester does with 13KB of markdown afterward. It doesn't resolve whether serving materially different content at the same URL based on user-agent is cloaking, which Lane points out is the textbook definition, and which BCG X's Rob Derow flags as the live risk: there are no rules yet for how LLMs treat markdown ads, and if the model vendors decide this is cloaking, those pages get less effective or penalized. Googlebot gets the human HTML, which reads as an exception TIME is making for the one crawler it can't afford to fork content for.
Signatures also do nothing for provenance downstream. TIME labels every unit as sponsored content, naming the brand, with no rule requiring it. But the label sits at the head of a block that runs from 41% to 70% of the bytes the crawler ingests, and a retrieval system that chunks the page will produce chunks of pure advertiser copy carrying TIME's domain authority and no disclosure at all. Disclosure at the top of a block doesn't survive chunking. That's a content-provenance problem, and it needs a different tool.
What signed identity does fix is the layer everything else is stacked on. You cannot enforce a per-agent policy, price a per-agent tier, honor a licensing agreement, or defend an impression count while the party identifier is a string anyone can type. Every one of those arguments currently ends in "well, they said they were ClaudeBot."
Regulators are pulling the same thread
New York passed the Stealth Crawler Prohibition Act in June 2026, requiring bots to disclose their identity and purpose, with civil penalties reaching $15,000 per day for each violation; it's awaiting the governor's signature. Companion legislation landed in the U.S. House in July. Media analyst Matthew Scott Goldstein put the commercial logic bluntly: "Every licensing conversation I sit in stalls at the same place, which is that publishers have no reliable way to prove what was taken, by whom, at what volume... Once a crawler has to say its name, scraping stops being free and starts being a line item."
A disclosure mandate and a signed-identity standard are answers to the same question from opposite directions. The law can compel a bot to say its name. Only the signature makes the name worth anything.
If you run an origin
Three things are worth doing this quarter, whether or not you ever sell an agent ad.
Audit what your own edge actually does. Fetch one of your URLs with a browser user-agent, then with ClaudeBot, OAI-SearchBot, PerplexityBot, GPTBot, and Googlebot, and diff the responses. Fetch twice more with the same bot agent to see what rotates per request. Then compare /llms.txt and /robots.txt against what the edge actually did. Run the whole thing from a second HTTP client, because if the two disagree you're measuring your tooling and not your site.
Decide what tier of identity each decision deserves. Rate limiting on a spoofable header is fine. Content forking is riskier. Billing, licensing enforcement, and access to a paid tier need a signature, and there is now a standard and a live verification path for getting one.
Treat agent identity as an authorization problem, not an analytics problem. Automated requests are already 57.5% of HTML web traffic on the roughly one-fifth of the web Cloudflare Radar observes, and 51.8% of AI crawler requests are for training with only 9.3% for search. TIME says bot traffic outnumbers human traffic on its own site most days. The majority of your callers are machines, most of them want your content rather than your product, and a growing number of them are attached to a price.
The ads are the least interesting part of TIME's experiment. What matters is that a publisher built a metering system on top of an unauthenticated claim and shipped it, and the first outsider to point a second HTTP client at it found the stated policy and the deployed behavior disagreeing. Every one of those 13,409-byte responses carried a fresh impression ID, and none of them carried proof of who was reading. If you're building the next one of these, start with the identity layer. It's the only part that can't be bolted on later.
Identity for agents, from WorkOS
Agents that read, buy, and transact on behalf of users need identity you can verify and authorization you can enforce. WorkOS provides OAuth 2.1 for scoped agent credentials, fine-grained authorization for resource-level access decisions, and native MCP server authentication, so your application can check who's asking instead of trusting a header it never controlled.