# Markdown versions checker

> Check which of your pages serve a markdown version: declared alternates, .md twins, Accept negotiation and how closely each version matches its page. Then copy a recipe for your platform.

This is the markdown version of https://llmsrank.dev/tools/markdown-versions. The tool is beta and free. Recipes and claims checked 2026-09-29. It doesn’t claim that any AI product reads markdown versions.

## The check

The check obeys your robots.txt for our tool token, LLMSRank-User: a page it disallows is skipped, never fetched, and listed in the results; if it disallows your homepage, no check is made. Your llms.txt and robots.txt are always read.

Enter a domain or an llms.txt URL on the page. We fetch the homepage and up to 25 pages your llms.txt links, as a different sample from the scan, and report per page: (a) the HTML status, (b) a declared markdown alternate and whether it works, (c) a guessed `.md` twin (a 200 that is HTML is reported as "HTML served at .md"), (d) `describedby`, (e) which URL your llms.txt links, HTML, markdown or both, and (f) whether `Accept: text/markdown` on the page URL answers markdown, and with `Vary: Accept`. Where both a page and a markdown version were read, a parity verdict with the shared word-run share (Jaccard), word counts and H2 headings missing from the markdown. The comparison reads server HTML only. The check counts as one of the free scans of the day. Programmatic use: `POST https://llmsrank.dev/api/tools/twins` with `{"target": "example.com"}`, then `GET` the `status_url` it returns.

## How we compare a page with its markdown version

Method dated 2026-09-29.

### A diagnostic, not a score

This check tells you whether your markdown version says the same thing as the web page it stands for. It does not count toward your LLMSRank score and does not change any audit result.

Nothing here says that an AI product reads markdown versions or that matching ones rank better. It only compares two files.

### What we compare

From the web page we take the text a visitor would read: we drop scripts, styles, navigation, headers, footers and sidebars, and use the <main> element when the page has one. We read the HTML your server sends and do not run JavaScript, so text that only appears after scripts run is not counted.

From the markdown version we take the text without markup. Both texts are split into overlapping runs of 5 words, and we report the share of runs the two have in common (Jaccard similarity: shared runs divided by all distinct runs). 100% means the same words in the same order.

We also list H2 headings on the page that the markdown version lacks, and links that point somewhere different.

### Verdicts

Matches: 70% or more of the word runs are shared.

Partial: 40% up to 70%.

Differs: under 40%.

Stub: the markdown version has fewer than 15% as many words as the page. This is reported instead of the other three.

### How we set the thresholds

On 2026-09-29 we compared 39 page and markdown pairs from 30 sites that already publish markdown versions, and read each pair ourselves. Every pair at 70% or more carried the same content. Faithful versions from documentation tools often land between 70% and 80%, because the web page repeats tab labels and button text ("curl Python JavaScript", "Copy page") between blocks. No pair fell between 30% and 53%, so the partial line sits in that gap. The two stubs we found had 2% and 4% of the page's words.

Most of the sample is developer documentation, so the thresholds are best tested there. We will revisit them as more sites publish markdown versions.

### When the verdict can mislead

Short or link-heavy pages (indexes, hubs, card grids): a few extra words such as "Read more" or item numbers break many word runs, so a faithful version can read as partial or differs.

Pages without navigation markup: menus and page tools that are not in <nav>, <header> or <aside> count as page text, so a clean markdown version looks shorter than the page.

API reference pages: some documentation tools publish the OpenAPI definition as the markdown version while the page shows code samples. Both describe the same endpoint, but the words differ.

Pages built by JavaScript: when the server sends little text, the markdown version can hold several times more words than the page, and the verdict says differs.

Rewritten or out-of-date versions: a summary written for AI readers, or a version not regenerated after the page changed, is reported as differs. That is the point of the check, but look at the headings and links lists before assuming the version is wrong.

Translated pages: compare a page with the markdown version in the same language. Different languages share almost no word runs.

## Add markdown versions on your platform

Each recipe says what the platform documents and where we wrote the code ourselves. "Not tested by us" means we have not yet run it on that platform. Recipes and claims checked 2026-09-29.

### Next.js (App Router)

Not tested by us.

Next.js has no built-in setting for this: PR #98807 (`markdownAgents`) was still open on 2026-09-29. A Next.js maintainer’s answer (discussion #90579, 2026-02-26) is a `rewrites()` rule on the `accept` request header that sends the request to a Route Handler returning `Content-Type: text/markdown; charset=utf-8` and `Vary: Accept`.

1. List the pages that have a markdown version, and write `getMarkdown(page)` from the same content your pages render.
2. Add the rewrites and headers to `next.config.mjs`: `/page.md` URLs, the same page URL answering `Accept: text/markdown`, and a `Link` header on the HTML page naming its markdown version and the llms.txt.
3. Add the Route Handler at `app/md/[[...slug]]/route.ts`. It answers `text/markdown; charset=utf-8` with `Vary: Accept`, and names the HTML page as canonical.
4. Check with curl, then with our tool.

`next.config.mjs`

```js
// next.config.mjs
// Pages that have a markdown version. Only these get the Accept rewrite and the Link header,
// so every other page keeps serving HTML and never advertises a 404.
const MARKDOWN_PAGES = ['/', '/pricing', '/docs/getting-started'];
const twinOf = (page) => (page === '/' ? '/index.md' : `${page}.md`);
const WANTS_MARKDOWN = { type: 'header', key: 'accept', value: '(.*)text/markdown(.*)' };

export default {
  async rewrites() {
    return {
      beforeFiles: [
        // /pricing.md (and /index.md) -> the markdown route handler
        { source: '/:path*.md', destination: '/md/:path*' },
        // /pricing with Accept: text/markdown -> the same handler, same URL for the client
        ...MARKDOWN_PAGES.map((page) => ({
          source: page,
          has: [WANTS_MARKDOWN],
          destination: page === '/' ? '/md' : `/md${page}`,
        })),
      ],
    };
  },
  async headers() {
    // HTML responses only (the handler sets its own headers on markdown responses).
    return MARKDOWN_PAGES.map((page) => ({
      source: page,
      missing: [WANTS_MARKDOWN],
      headers: [
        { key: 'Link', value: `<${twinOf(page)}>; rel="alternate"; type="text/markdown", </llms.txt>; rel="describedby"` },
        { key: 'Vary', value: 'Accept' },
      ],
    }));
  },
};
```

`app/md/[[...slug]]/route.ts`

```ts
// app/md/[[...slug]]/route.ts
import { getMarkdown } from '@/lib/markdown'; // yours: the page's markdown, or null

const MARKDOWN = 'text/markdown; charset=utf-8';

export async function GET(_request: Request, { params }: { params: Promise<{ slug?: string[] }> }) {
  const { slug = [] } = await params;
  const page = slug.length === 0 || slug.join('/') === 'index' ? '/' : `/${slug.join('/')}`;
  const markdown = await getMarkdown(page);
  if (markdown === null) {
    return new Response('# Not found\n', { status: 404, headers: { 'Content-Type': MARKDOWN, Vary: 'Accept' } });
  }
  return new Response(markdown, {
    headers: {
      'Content-Type': MARKDOWN,
      Vary: 'Accept',
      // The llms.txt that covers the page, and the HTML page as canonical.
      Link: `</llms.txt>; rel="describedby", <${page}>; rel="canonical"`,
    },
  });
}
```

`check`

```bash
curl -sI https://example.com/pricing | grep -iE '^(link|vary):'
curl -s -H 'Accept: text/markdown' https://example.com/pricing | head
curl -sI https://example.com/pricing.md | grep -iE '^(content-type|link):'
```

- Vercel’s blog example (2026-02-03) sends `Content-Type: text/markdown` without a charset and without `Vary: Accept`. We add both: RFC 7763 requires the charset parameter, and `Vary: Accept` tells caches that the same URL has an HTML and a markdown answer. Sources: [Vercel blog: Making agent-friendly pages with content negotiation](https://vercel.com/blog/making-agent-friendly-pages-with-content-negotiation) (checked 2026-09-29); [Vercel Knowledge Base: How to serve documentation for agents](https://vercel.com/kb/guide/how-to-serve-documentation-for-agents) (checked 2026-09-29); [RFC 7763: The text/markdown Media Type](https://www.rfc-editor.org/rfc/rfc7763) (checked 2026-09-29).
- The accept rule matches any `Accept` header that contains `text/markdown`, whatever its q-value. Browsers don’t send `text/markdown`, so they keep getting HTML. Sources: [Next.js discussion #90579: a maintainer’s answer on serving markdown for Accept: text/markdown (rewrite on the accept header to a route handler)](https://github.com/vercel/next.js/discussions/90579) (checked 2026-09-29); [Checkly: The state of AI agent content negotiation (seven agents fetched httpbin.org/headers)](https://www.checklyhq.com/blog/state-of-ai-agent-content-negotation/) (checked 2026-09-29).
- Only the listed pages negotiate. A page without a markdown version keeps serving HTML to every client, and no page advertises a markdown version that doesn’t exist. Sources: [Markdown page versions and link relations (our guide, incl. “Don’t advertise a 404”)](https://llmsrank.dev/learn/markdown-pages) (checked 2026-09-29).
- The `Link` and `Content-Type` values are the ones our own pages and `.md` versions send. Our site serves `.md` URLs without Accept negotiation, so `Vary: Accept` is the one header here that our site doesn’t send. Sources: [The Link and Content-Type headers our own pages and .md versions send](https://llmsrank.dev/index.md) (checked 2026-09-29).
- Next.js adds its own values to `Vary` on page responses. Check the final header with the curl commands above. Sources: [Next.js source: setVaryHeader in base-server.ts (appends its own Vary values to page responses; read in next 15.5.20)](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/base-server.ts) (checked 2026-09-29).

Sources for this recipe: [Next.js discussion #90579: a maintainer’s answer on serving markdown for Accept: text/markdown (rewrite on the accept header to a route handler)](https://github.com/vercel/next.js/discussions/90579) (checked 2026-09-29); [Next.js PR #98807 “feat: add markdownAgents content negotiation” (open; last activity 2026-09-17)](https://github.com/vercel/next.js/pull/98807) (checked 2026-09-29); [Next.js source: setVaryHeader in base-server.ts (appends its own Vary values to page responses; read in next 15.5.20)](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/base-server.ts) (checked 2026-09-29); [Vercel blog: Making agent-friendly pages with content negotiation](https://vercel.com/blog/making-agent-friendly-pages-with-content-negotiation) (checked 2026-09-29); [Vercel Knowledge Base: How to serve documentation for agents](https://vercel.com/kb/guide/how-to-serve-documentation-for-agents) (checked 2026-09-29); [RFC 7763: The text/markdown Media Type](https://www.rfc-editor.org/rfc/rfc7763) (checked 2026-09-29); [The Link and Content-Type headers our own pages and .md versions send](https://llmsrank.dev/index.md) (checked 2026-09-29); [Markdown page versions and link relations (our guide, incl. “Don’t advertise a 404”)](https://llmsrank.dev/learn/markdown-pages) (checked 2026-09-29).

### Vercel, any framework (vercel.json)

Not tested by us.

Vercel has no project setting for markdown versions. Vercel’s own docs answer in markdown at the page URL and at a `.md` URL, but that page describes Vercel’s docs site, not a customer setting. `vercel.json` headers and rewrites accept `has` and `missing` conditions on request headers.

1. Build a `.md` file next to each page that has a markdown version (for example `/pricing.md`).
2. Add the headers: `text/markdown; charset=utf-8` on `.md` files, and on each HTML page a `Link` header naming its markdown version and the llms.txt.
3. Add a rewrite per page on `Accept: text/markdown`, if the page is served by a function or framework route (see the caution).
4. Deploy a preview and check with curl, then with our tool.

`vercel.json`

```json
{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "headers": [
    {
      "source": "/(.*)\\.md",
      "headers": [
        { "key": "Content-Type", "value": "text/markdown; charset=utf-8" },
        { "key": "Link", "value": "</llms.txt>; rel=\"describedby\"" }
      ]
    },
    {
      "source": "/pricing",
      "headers": [{ "key": "Vary", "value": "Accept" }]
    },
    {
      "source": "/pricing",
      "missing": [{ "type": "header", "key": "accept", "value": "(.*)text/markdown(.*)" }],
      "headers": [
        { "key": "Link", "value": "</pricing.md>; rel=\"alternate\"; type=\"text/markdown\", </llms.txt>; rel=\"describedby\"" }
      ]
    }
  ],
  "rewrites": [
    {
      "source": "/pricing",
      "has": [{ "type": "header", "key": "accept", "value": "(.*)text/markdown(.*)" }],
      "destination": "/pricing.md"
    }
  ]
}
```

Caution: Vercel’s docs say a rewrite’s source “should NOT be a file because precedence is given to the filesystem prior to rewrites being applied”. On a static site, where `/pricing` is a file, the `Accept` rewrite won’t run; the `.md` URLs and `Link` headers still work. Sources: [Vercel docs: Static Configuration with vercel.json (headers, rewrites, has and missing)](https://vercel.com/docs/project-configuration/vercel-json) (checked 2026-09-29).

Caution: Vercel’s docs say “Using `has` does not yet work locally while using `vercel dev`, but does work when deployed.” Test on a preview deployment. Sources: [Vercel docs: Static Configuration with vercel.json (headers, rewrites, has and missing)](https://vercel.com/docs/project-configuration/vercel-json) (checked 2026-09-29).

- With Next.js on Vercel, use the Next.js recipe instead. Sources: [Vercel docs: Static Configuration with vercel.json (headers, rewrites, has and missing)](https://vercel.com/docs/project-configuration/vercel-json) (checked 2026-09-29).

Sources for this recipe: [Vercel docs: Static Configuration with vercel.json (headers, rewrites, has and missing)](https://vercel.com/docs/project-configuration/vercel-json) (checked 2026-09-29); [Vercel docs: Markdown and Agent Discovery (how Vercel’s own docs serve markdown)](https://vercel.com/docs/agent-resources/markdown-access) (checked 2026-09-29).

### Cloudflare

Not tested by us.

Markdown for Agents converts a page’s HTML to markdown at Cloudflare when the request’s `Accept` header asks for `text/markdown`. Cloudflare’s reference lists Pro, Business and Enterprise plans and SSL for SaaS customers; the Free plan is not listed. Turn it on in the dashboard under AI Crawl Control, or with the zone setting `content_converter`.

1. Dashboard: AI Crawl Control → Markdown for Agents → on. Or use the API call below.
2. Set your own `content-signal` header at your origin if you don’t want the default (see the caution).
3. Check a page with `Accept: text/markdown`.
4. For `.md` URLs, add the Worker below. It is our recipe: Cloudflare doesn’t document `.md` URLs.

`turn on and check`

```bash
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/settings/content_converter" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"value":"on"}'

# Check: the same URL, asking for markdown
curl -sI -H 'Accept: text/markdown' https://example.com/pricing | grep -iE '^(content-type|vary|content-signal|x-markdown-tokens):'
```

`worker.js`: Our recipe, not Cloudflare’s. Cloudflare doesn’t document whether a Worker’s request to its own zone is converted; not verified. If it isn’t, the Worker answers 404 rather than serve HTML as markdown.

```js
// worker.js: .md URLs on a zone with Markdown for Agents on. Our recipe; Cloudflare doesn't
// document .md URLs. /pricing.md asks the zone for /pricing with Accept: text/markdown and serves
// the answer only if it came back as markdown, so HTML is never labelled as markdown.
// Leave ADVERTISE off until you have checked that /pricing.md answers 200 on your zone.
const ADVERTISE = false;

const pageOf = (path) => (path === '/index.md' ? '/' : path.slice(0, -'.md'.length));
const twinOf = (path) => (path === '/' ? '/index.md' : `${path.replace(/\/$/, '')}.md`);

export default {
  async fetch(request) {
    const url = new URL(request.url);
    const isMd = url.pathname.endsWith('.md');
    if (!isMd || (request.method !== 'GET' && request.method !== 'HEAD')) {
      const response = await fetch(request);
      const type = response.headers.get('content-type') || '';
      if (!ADVERTISE || isMd || response.status !== 200 || !type.startsWith('text/html')) return response;
      const withLink = new Response(response.body, response);
      withLink.headers.append('Link', `<${twinOf(url.pathname)}>; rel="alternate"; type="text/markdown"`);
      withLink.headers.append('Vary', 'Accept');
      return withLink;
    }
    const page = new URL(url);
    page.pathname = pageOf(url.pathname);
    const upstream = await fetch(page, { method: request.method, headers: { Accept: 'text/markdown' } });
    const type = upstream.headers.get('content-type') || '';
    if (upstream.status !== 200 || !type.startsWith('text/markdown')) {
      return new Response('Not found\n', { status: 404, headers: { 'Content-Type': 'text/plain; charset=utf-8' } });
    }
    const headers = new Headers({
      'Content-Type': 'text/markdown; charset=utf-8',
      Link: `<${page.pathname}>; rel="canonical"`,
    });
    for (const name of ['content-signal', 'x-markdown-tokens', 'cache-control']) {
      const value = upstream.headers.get(name);
      if (value) headers.set(name, value);
    }
    return new Response(upstream.body, { status: 200, headers });
  },
};
```

Caution: When your origin doesn’t send a `content-signal` header, Markdown for Agents adds `content-signal: ai-train=yes, search=yes, ai-input=yes` to converted responses, which says the content may be used for AI training. If you disagree, send your own `content-signal` header from your origin; Cloudflare keeps the origin’s value. Sources: [Cloudflare docs: Markdown for Agents (reference)](https://developers.cloudflare.com/fundamentals/reference/markdown-for-agents/) (checked 2026-09-29); [Cloudflare changelog: Introducing Markdown for Agents](https://developers.cloudflare.com/changelog/post/2026-02-12-markdown-for-agents/) (checked 2026-09-29).

- Converted responses carry `x-markdown-tokens` (an estimated token count) and `Vary: Accept`. Cloudflare converts HTML only, and the origin response can’t exceed 2 MB. Sources: [Cloudflare docs: Markdown for Agents (reference)](https://developers.cloudflare.com/fundamentals/reference/markdown-for-agents/) (checked 2026-09-29).
- Cloudflare documents no `.md` URLs and no `rel="alternate"` link for converted pages. The Worker can add both; leave its `ADVERTISE` switch off until `/page.md` answers on your zone, so no page advertises a 404. Sources: [Cloudflare docs: Markdown for Agents (reference)](https://developers.cloudflare.com/fundamentals/reference/markdown-for-agents/) (checked 2026-09-29); [Markdown page versions and link relations (our guide, incl. “Don’t advertise a 404”)](https://llmsrank.dev/learn/markdown-pages) (checked 2026-09-29).

Sources for this recipe: [Cloudflare docs: Markdown for Agents (reference)](https://developers.cloudflare.com/fundamentals/reference/markdown-for-agents/) (checked 2026-09-29); [Cloudflare changelog: Introducing Markdown for Agents](https://developers.cloudflare.com/changelog/post/2026-02-12-markdown-for-agents/) (checked 2026-09-29).

### WordPress

Not tested by us.

We found no WordPress core setting for markdown versions. The plugins below add them. They are listed alphabetically; we don’t rank or endorse them. After installing one, check the result with our tool.

1. Markdown Alternate (GitHub only, not in the WordPress.org directory; by Joost de Valk, ProgressPlanner): `.md` URLs, `?format=markdown`, and a `<link rel="alternate" type="text/markdown">` in each page’s `<head>`. A request with `Accept: text/markdown` gets a 303 redirect to the `.md` URL. Markdown responses send `text/markdown; charset=UTF-8`, `Vary: Accept`, a canonical `Link` and `X-Markdown-Tokens`.
2. Post Content to Markdown (GitHub only, not in the WordPress.org directory; by Roots): `Accept: text/markdown` on the post’s own URL returns markdown, plus `.md` URLs, `?format=markdown` and a `/feed/markdown/` feed. It sends `Vary: Accept`, and advertises the markdown version with a `Link` header and a `<link>` element (`rel="alternate"; type="text/markdown"`). The charset in its `Content-Type` is the site’s own charset setting.
3. Serve Markdown (`serve-md`, WordPress.org directory, by Azey): per its directory page, `Accept: text/markdown`, `.md` URLs and a `<link rel="alternate" type="text/markdown">` in the page head, with YAML front matter and per-post opt-out. We haven’t read its source.
4. Yoast SEO’s llms.txt feature: its help page describes generating an llms.txt file. It doesn’t describe markdown versions of pages.

Sources for this recipe: [Markdown Alternate (ProgressPlanner/markdown-alternate on GitHub), version 1.1.0; source read at the commit of 2026-06-15](https://github.com/progressplanner/markdown-alternate) (checked 2026-09-29); [Joost de Valk: My WordPress take on Markdown for Agents](https://joost.blog/markdown-alternate/) (checked 2026-09-29); [Post Content to Markdown (roots/post-content-to-markdown on GitHub), version 1.7.1; source read at the commit of 2026-05-07](https://github.com/roots/post-content-to-markdown) (checked 2026-09-29); [Serve Markdown (serve-md) in the WordPress.org plugin directory, version 1.0](https://wordpress.org/plugins/serve-md/) (checked 2026-09-29); [WordPress.org plugin directory API (slugs markdown-alternate and post-content-to-markdown: “Plugin not found”)](https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&request%5Bslug%5D=markdown-alternate) (checked 2026-09-29); [Yoast help: How to enable llms.txt](https://yoast.com/help/enable-llmstxt/) (checked 2026-09-29).

### Mintlify

Not tested by us.

Built in. Mintlify serves a markdown version at the page URL plus `.md`, and at the page URL for `Accept: text/markdown` or `Accept: text/plain`. It generates llms.txt and llms-full.txt; a file of your own with the same name replaces the generated one. It sends `Link: </llms.txt>; rel="llms-txt"` and `X-Llms-Txt` headers.

1. Nothing to add for markdown versions.
2. If you publish your own llms.txt, link the `.md` forms of your pages.
3. Check with our tool.

- On 2026-09-29 Mintlify’s own docs page had a `<link rel="alternate" type="text/markdown">` in its `<head>` and sent `Vary: accept`. That is what we saw on one site; Mintlify’s docs don’t describe it. Sources: [Our requests to mintlify.com/docs/ai/markdown-export on 2026-09-29 (response headers and <head>)](https://www.mintlify.com/docs/ai/markdown-export) (checked 2026-09-29).

Sources for this recipe: [Mintlify docs: Markdown export](https://www.mintlify.com/docs/ai/markdown-export) (checked 2026-09-29); [Mintlify docs: llms.txt](https://www.mintlify.com/docs/ai/llmstxt) (checked 2026-09-29); [Mintlify blog: content negotiation and Link / X-Llms-Txt headers for agents](https://www.mintlify.com/blog/context-for-agents) (checked 2026-09-29).

### Netlify

Not tested by us.

Netlify publishes a prompt template for an AI coding assistant: it builds an Edge Function that converts HTML to markdown with Turndown when a request sends `Accept: text/markdown`.

1. Read Netlify’s template.

- The template’s header list includes `Content-Signal: ai-train=yes, search=yes, ai-input=yes`, which allows AI training; change it if you disagree. It doesn’t mention `Vary: Accept`; add it. Sources: [Netlify docs: Markdown for Agents prompt template](https://docs.netlify.com/prompt-templates/netlify/markdown-for-agents/) (checked 2026-09-29).

Sources for this recipe: [Netlify docs: Markdown for Agents prompt template](https://docs.netlify.com/prompt-templates/netlify/markdown-for-agents/) (checked 2026-09-29).

## What we know and don’t

- We found no vendor document saying that its agents act on `rel="alternate" type="text/markdown"` links (checked 2026-09-29). The one claim we found is third-party testing: acceptmarkdown.com reports, as of 2026-06-22, that Codex CLI fetched a page as HTML and then requested the `.md` link named in its `<head>`. Sources: [Does ChatGPT, Claude, Perplexity or Google read llms.txt? (vendor statements, checked 2026-09-29)](https://llmsrank.dev/learn/does-ai-read-llms-txt) (checked 2026-09-29); [acceptmarkdown.com: agent status table (third-party testing)](https://acceptmarkdown.com/status) (checked 2026-09-29).
- In a third-party test published 2026-02-19, Checkly had seven coding agents fetch a URL that echoes request headers. Three sent `Accept: text/markdown`: Claude Code (v2.1.38), Cursor (2.4.28) and OpenCode (1.2.5). OpenAI Codex, Gemini CLI, GitHub Copilot and Windsurf did not. Agents change between versions. Sources: [Checkly: The state of AI agent content negotiation (seven agents fetched httpbin.org/headers)](https://www.checklyhq.com/blog/state-of-ai-agent-content-negotation/) (checked 2026-09-29).
- `text/markdown` is registered by RFC 7763, which makes the `charset` parameter required: send `Content-Type: text/markdown; charset=utf-8`. Sources: [RFC 7763: The text/markdown Media Type](https://www.rfc-editor.org/rfc/rfc7763) (checked 2026-09-29).
- Google’s Search Central guide (updated 2026-07-10) says you don’t need Markdown to appear in Google Search, “as Google Search itself doesn’t use them.” Markdown versions are for agents and tools that ask for them. Sources: [Google Search Central: Optimizing your website for generative AI features on Google Search](https://developers.google.com/search/docs/fundamentals/ai-optimization-guide) (checked 2026-09-29).
