A Cloudflare site serves markdown to an AI agent when the request Accept header includes text/markdown. Markdown for Agents does that conversion at the edge on Pro, Business, and Enterprise zones, and for SSL for SaaS customers. A Worker on the Workers Free or Workers Paid plan can convert the HTML itself with env.AI.toMarkdown().
Key facts
- Cloudflare published Markdown for Agents on 2026-02-12. On 2026-02-16 it raised the origin response limit from 1 MB to 2 MB, 2,097,152 bytes, stopped requiring
Content-Lengthfrom the origin, and started converting content-encoded origin responses. - Markdown for Agents is included at no extra charge on Pro, Business, and Enterprise plans, and for SSL for SaaS customers. That availability list does not include the Free zone plan.
- Workers AI, including
env.AI.toMarkdown(), is included on the Workers Free and Workers Paid plans. ThetoMarkdownoverview says most format conversions are free. Image conversion can call Workers AI models and may spend Neurons past the daily free allocation. The HTML path stripsscriptandstyletags and does not name a model. - Workers AI includes 10,000 Neurons per day at no charge on Workers Free and Workers Paid. Usage above that on Workers Paid costs $0.011 per 1,000 Neurons. The pricing page says it was last updated on 2026-10-01.
- Cloudflare's 2026-02-12 announcement measured that post at 16,180 tokens as HTML and 3,150 tokens as markdown, and called the difference an 80% reduction.
- On 2026-02-19, Checkly had seven coding agents fetch
https://httpbin.org/headers. Claude Code v2.1.38, Cursor 2.4.28, and OpenCode 1.2.5 sentAccept: text/markdown. Codex 260203.1501, Gemini CLI 0.28.2, GitHub Copilot on GPT-5.2-Codex, and Windsurf 1.9552.21 did not. - On 2026-04-17, Cloudflare Radar said markdown content negotiation passed on 3.9% of sites. The scan started from the 200,000 most visited domains, then dropped categories such as redirects, ad servers, and tunneling services. The post says the chart updates weekly.
How Accept: text/markdown content negotiation works
HTTP content negotiation lets a client name a preferred media type in the Accept header. An agent that sends Accept: text/markdown is asking for markdown. A converted response uses Content-Type: text/markdown; charset=utf-8 and Vary: Accept, so a cache can store the HTML and markdown responses separately. Markdown for Agents also sends x-markdown-tokens and x-original-tokens.
This request asks https://insidetheloop.dev/ for markdown:
curl -i -H 'Accept: text/markdown' https://insidetheloop.dev/At 2026-10-05 22:07:52 GMT the response headers that describe the negotiation, and the full 824-byte body, were:
HTTP/2 200
content-type: text/markdown; charset=utf-8
content-length: 824
link: </llms.txt>; rel="describedby"; type="text/plain", </sitemap.xml>; rel="describedby"; type="application/xml", </rss.xml>; rel="alternate"; type="application/rss+xml"
vary: Accept
x-markdown-tokens: 206
---
description: Field notes on agentic anything: Claude Code, Codex, Cursor and whatever ships next.
title: Inside the Loop
---
[Oct 5, 20266 minHow AI agents fetch web pages: user agents, IP ranges, and fetch originsAI crawlers fetch from vendor datacenters using published IP ranges, while CLI coding agents fetch directly from developer workstations via local IPs.](/posts/how-ai-agents-fetch-web-pages-user-agents)
[Oct 5, 20266 minHow to pass every isitagentready.com check for a content sitePassing the seven isitagentready.com content checks requires a valid robots.txt, sitemap, Link headers, markdown negotiation, Content Signals, and DNS-AID.](/posts/isitagentready-content-site-checks)
{"@context":"https://schema.org","@type":"WebSite","name":"Inside the Loop","url":"https://insidetheloop.dev"}
toMarkdown joined each post card's date, reading time, title, and excerpt into one link. The same URL without Accept: text/markdown returned a 22,739-byte HTML body in that same second. 824 / 22,739 is 3.62% of that HTML body.
Cloudflare Markdown for Agents versus Workers AI toMarkdown
Cloudflare documents two ways to answer Accept: text/markdown. Markdown for Agents is a zone setting. env.AI.toMarkdown() is a Workers AI method the Worker calls itself. The Markdown for Agents docs point HTML cleanup at the same Workers AI pre-processing page: drop script and style, pull title, description, and image meta tags into YAML front matter, and append JSON-LD in one json code block.
Feature | Markdown for Agents | Workers AI |
|---|---|---|
Plan | Pro, Business, Enterprise, and SSL for SaaS | Workers Free and Workers Paid |
Setup | Dashboard toggle or a configuration rule | Worker code and an |
Origin size | 2,097,152 bytes since 2026-02-16 | No separate HTML byte cap in the toMarkdown docs |
Token headers |
|
|
Price | Included at no extra charge on those zone plans | Free for most formats. Image conversion can spend Neurons |
Cache headers | Keeps origin cache headers and adds | Whatever headers the Worker sets |
Implementing toMarkdown in a Cloudflare Worker
This site declares the Workers AI binding in wrangler.jsonc:
"ai": {
"binding": "AI"
}src/worker.ts in this site checks the HTML response, and on Accept: text/markdown sends the body to env.AI.toMarkdown(). If conversion fails, the same function returns the HTML response. LINK is the site's Link header value, and CONTENT_SIGNAL is the robots.txt content-signal line.
const CONTENT_SIGNAL = "Content-Signal: search=yes, ai-input=yes, ai-train=yes";
const LINK = '</llms.txt>; rel="describedby"; type="text/plain", </sitemap.xml>; rel="describedby"; type="application/xml", </rss.xml>; rel="alternate"; type="application/rss+xml"';
async function withAgentSignals(request: Request, url: URL, res: Response, env: Env): Promise<Response> {
if (url.pathname === "/robots.txt" && res.ok) {
const body = (await res.text()).replace(/^(User-agent: \*\s*\n)/m, `$1${CONTENT_SIGNAL}\n`);
return new Response(body, res);
}
if (!(res.headers.get("content-type") ?? "").startsWith("text/html")) return res;
// Markdown for agents: Accept: text/markdown gets the page converted by Workers AI.
if (res.ok && (request.headers.get("accept") ?? "").includes("text/markdown")) {
try {
const html = await res.clone().text();
const [doc] = await env.AI.toMarkdown([{ name: "page.html", blob: new Blob([html], { type: "text/html" }) }]);
if (doc && doc.format === "markdown") {
const headers = new Headers({ "content-type": "text/markdown; charset=utf-8", vary: "Accept", link: LINK });
if (doc.tokens) headers.set("x-markdown-tokens", String(doc.tokens));
return new Response(doc.data, { status: 200, headers });
}
} catch {
// fall through to HTML
}
}
const out = new Response(res.body, res);
out.headers.append("Link", LINK);
out.headers.append("Vary", "Accept");
return out;
}How Cloudflare Docs serves agents that omit Accept
Checkly's test on 2026-02-19 found that four of the seven agents it tried did not send Accept: text/markdown. Cloudflare's docs, described in the 2026-04-17 Agent Readiness post, add a URL fallback so those clients still get markdown:
- A URL Rewrite Rule matches a path ending in
/index.mdand rewrites it to the page path. - A Request Header Transform Rule matches the original path,
raw.http.request.uri.path, and setsAccept: text/markdown.
The docs llms.txt files link to those /index.md URLs. A request for /index.md then returns markdown even when the client sends no Accept preference.
Measured size of HTML and markdown
At 2026-10-05 22:07:52 GMT, https://insidetheloop.dev/ returned a 22,739-byte HTML body. The Accept: text/markdown response was 824 bytes, 3.62% of that HTML body, and the x-markdown-tokens header was 206.
Cloudflare's 2026-02-12 announcement used a different page, that blog post itself: 16,180 HTML tokens and 3,150 markdown tokens. Cloudflare called that an 80% reduction.
Sources
- HTTP content negotiation: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Content_negotiation (read 2026-10-06)
- Introducing Markdown for Agents changelog: https://developers.cloudflare.com/changelog/post/2026-02-12-markdown-for-agents/ (read 2026-10-06)
- Markdown for Agents follow-up, origin limit and content encoding: https://developers.cloudflare.com/changelog/post/2026-02-16-markdown-for-agents-improvements/ (read 2026-10-06)
- Markdown for Agents reference: https://developers.cloudflare.com/fundamentals/reference/markdown-for-agents/ (read 2026-10-06)
- Introducing Markdown for Agents: https://blog.cloudflare.com/markdown-for-agents/ (read 2026-10-06)
- Introducing the Agent Readiness score: https://blog.cloudflare.com/agent-readiness/ (read 2026-10-06)
- The Current State of Content Negotiation for AI Agents: https://www.checklyhq.com/blog/state-of-ai-agent-content-negotation/ (read 2026-10-06)
- Workers AI Markdown Conversion: https://developers.cloudflare.com/workers-ai/features/markdown-conversion/ (read 2026-10-06)
- Workers AI Markdown Conversion, how it works: https://developers.cloudflare.com/workers-ai/features/markdown-conversion/how-it-works/ (read 2026-10-06)
- Workers AI binding: https://developers.cloudflare.com/workers-ai/features/markdown-conversion/usage/binding/ (read 2026-10-06)
- Workers AI pricing: https://developers.cloudflare.com/workers-ai/platform/pricing/ (read 2026-10-06)
- Inside the Loop homepage, HTML and
Accept: text/markdown: https://insidetheloop.dev/ (read 2026-10-06)
Last verified: 2026-10-06.