Accept: text/markdown · The authoritative guide · mdream

[All guides](https://mdream.dev/guides/accept-markdown-header/guides)

Guide

# The accept-markdown header

Accept: text/markdown is an HTTP content-negotiation header that signals an AI agent prefers clean markdown over HTML. Implementing it correctly means a Content-Type match, a Vary: Accept header, honoring q-values, and 406 on unsatisfiable requests.

Updated 2026-04-22

## [What the header is](#what-the-header-is)

`Accept: text/markdown` is an [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110#name-accept) content-negotiation header. A client tells the server "I can handle markdown, and I prefer it". The server then picks the best representation it can serve.

Example request:

```
GET /docs/api HTTP/1.1
Accept: text/markdown;q=1.0, text/html;q=0.8, */*;q=0.1
User-Agent: Cursor/1.5
```

Example response:

```
HTTP/1.1 200 OK
Content-Type: text/markdown; charset=utf-8
Vary: Accept
Content-Length: 4137
```

## [Correct implementation: the four things](#correct-implementation-the-four-things)

### [1. Serve the right Content-Type](#_1-serve-the-right-content-type)

If the client sends `Accept: text/markdown` and you have a markdown representation, return `Content-Type: text/markdown; charset=utf-8`.

### [2. Set Vary: Accept {#vary}](#_2-set-vary-accept-vary)

Without it, downstream caches will mix HTML and markdown responses under the same cache key. This is the single most common implementation bug.

### [3. Honor q-values {#q-values}](#_3-honor-q-values-q-values)

`Accept: text/html;q=0.9, text/markdown;q=1.0` means "prefer markdown but accept html". Serve markdown.

### [4. 406 on unsatisfiable Accept {#406}](#_4-406-on-unsatisfiable-accept-406)

If a client sends `Accept: application/vnd.pandoc` and you can't produce that format, returning 406 Not Acceptable is the spec-compliant response. Rarely required, but it's the mark of a serious implementation.

## [Cloudflare Workers example](#cloudflare-workers-example)

```
export default {
  async fetch(req: Request) {
    const accept = req.headers.get('accept') || ''
    const prefersMarkdown = /text\/markdown/.test(accept)
      && !/text\/html/.test(accept.split(',')[0])

    const pageUrl = new URL(req.url)
    const htmlRes = await fetch(pageUrl.toString())

    if (!prefersMarkdown) {
      const res = new Response(htmlRes.body, htmlRes)
      res.headers.set('Vary', 'Accept')
      return res
    }

    const html = await htmlRes.text()
    const markdown = convertHtmlToMarkdown(html) // e.g. mdream
    return new Response(markdown, {
      headers: {
        'Content-Type': 'text/markdown; charset=utf-8',
        'Vary': 'Accept',
      },
    })
  },
}
```

## [Vercel middleware example](#vercel-middleware-example)

```
import { NextResponse } from 'next/server'

export function middleware(req: Request) {
  const accept = req.headers.get('accept') || ''
  const wantsMd = accept.includes('text/markdown')

  const res = wantsMd
    ? NextResponse.rewrite(new URL(\`/api/render-md?u=${req.url}\`, req.url))
    : NextResponse.next()

  res.headers.set('Vary', 'Accept')
  return res
}
```

## [Verify](#verify)

[Use our tester](https://mdream.dev/guides/accept-markdown-header/tools/accept-header) to replay Claude Code, Cursor, and Codex requests against your URL and confirm all four checks pass.

## [Spec references](#spec-references)

- [RFC 9110 §12.5.1 — Accept](https://www.rfc-editor.org/rfc/rfc9110#name-accept)
- [RFC 9110 §8.3 — Content-Type](https://www.rfc-editor.org/rfc/rfc9110#field.content-type)
- [RFC 9111 §4.1 — Vary](https://www.rfc-editor.org/rfc/rfc9111#name-calculating-cache-keys-with)

## Check this on your site

[<h3>AI search visibility audit</h3>One-click audit: llms.txt, Accept-header, robots.txt, sitemap.md, token savings.](https://mdream.dev/guides/accept-markdown-header/tools/ai-audit)

## Related guides

[<h3>Generative engine optimization (GEO)</h3>Generative engine optimization (GEO) is the discipline of getting your content cited by ChatGPT, Claude, Perplexity, and Google AI Overviews. It blends classic SEO, structured data, and new formats like llms.txt + Accept-header markdown.](https://mdream.dev/guides/accept-markdown-header/guides/generative-engine-optimization) [<h3>Answer engine optimization (AEO)</h3>Answer engine optimization (AEO) is the practice of structuring content so that ChatGPT, Claude, Perplexity, Google AI Overviews, and voice assistants pick it as the canonical answer.](https://mdream.dev/guides/accept-markdown-header/guides/answer-engine-optimization) [<h3>Markdown for agents</h3>AI agents read markdown 2–5× more efficiently than HTML. Serve it via Accept-header negotiation, sitemap.md, and <link rel="alternate" type="text/markdown"> and every agent-originated request instantly becomes cheaper and smarter.](https://mdream.dev/guides/accept-markdown-header/guides/markdown-for-agents)

© 2026 [Harlan Wilton](https://github.com/harlan-zw) · [MIT](https://github.com/harlan-zw/mdream/blob/main/license)

[GitHub](https://github.com/harlan-zw/mdream) [Discord](https://discord.com/invite/275MBUBvgP)