# The Accept: text/markdown convention

What agent clients send, what your server should match on, and the exact media-type string defined by RFC 7763.

The media type registered with IANA for Markdown is **`text/markdown`**,
defined in [RFC 7763](https://www.rfc-editor.org/rfc/rfc7763). That's
the string clients should send in `Accept`, and the string your server
should send in `Content-Type`.

## What agent clients actually send

Most well-behaved agent clients send something like one of these:

```
Accept: text/markdown
Accept: text/markdown, text/html;q=0.8
Accept: text/markdown, text/plain;q=0.5, */*;q=0.1
```

The first preference is `text/markdown`. If the server can't do that,
the client falls back to HTML or plain text. The `q=0.8` means "accept
HTML at 80% of the preference given to Markdown."

Some clients are lazier and send `Accept: text/plain` or `*/*`. Those
aren't asking for Markdown specifically, so your server should serve
HTML (or whatever your default is).

## What your server should match on

Don't substring-match on `text/markdown`. A naive `accept.includes("text/markdown")`
happens to work, but
`accept.startsWith("text/html")` breaks on real Chrome headers. Use a
proper Accept parser — see
[Accept parsing & q-values](/guides/accept-parsing) for what to watch
for.

The short version: parse the header into an ordered list of type +
q-value, sort by q, break ties by specificity (more specific wins
over wildcards), and pick the highest-ranked type you can produce.

## Content-Type on the response

If you served Markdown, say so:

```http
Content-Type: text/markdown; charset=utf-8
```

The `charset=utf-8` parameter is a good idea — Markdown is just text,
but explicit is safer.

## Optional: the `variant` parameter

RFC 7764 defines a `variant` parameter for distinguishing Markdown
flavors:

```http
Content-Type: text/markdown; charset=utf-8; variant=CommonMark
Content-Type: text/markdown; charset=utf-8; variant=GFM
```

The variant parameter is uncommon in public traffic, and most clients
don't request it. You don't need it. But if you're being thorough about
which flavor of Markdown you serve, it's there.

## What *not* to use

- **`text/x-markdown`** — deprecated, predates the registration
- **`application/markdown`** — not registered, not conventional

## Related but not the same

- **`.md` in the URL path** (`/article.md` as a sibling of `/article`)
  is fine to ship, but agents have no way to discover it. They hit the
  canonical URL — `/article` — and read whatever it returns. If that's
  HTML, HTML is what ends up in their context.
- `/llms.txt` is sometimes proposed as a way to advertise sibling URLs
  to agents, but adoption in the wild is thin — don't count on it.
- Content negotiation via `Accept: text/markdown` on the canonical URL
  doesn't require discovery. The agent hits the URL it already knows.
  Your server picks the right bytes. Every HTTP client speaks Accept —
  that's the difference.
- Ship `.md` siblings if you want; they don't hurt. Just don't rely on
  them as the only path.

## Advertising `.md` siblings via `Link` / `rel="alternate"`

If you do ship siblings and want to make them discoverable, advertise
them per [RFC 8288](https://www.rfc-editor.org/rfc/rfc8288) — either as
an HTTP `Link` header or an HTML `<link>` element:

```http
Link: </article.md>; rel="alternate"; type="text/markdown"
```

```html
<link rel="alternate" type="text/markdown" href="/article.md">
```

Both declare "the same resource is also available at this URL in this
format." Agents and search engines that parse `rel="alternate"` can
follow it. Adoption in real-world agents is thin today, but the
markup is spec-compliant and costs nothing.

This is complementary to content negotiation, not a substitute. If you
have both, hitting `/article` with `Accept: text/markdown` still works
for any agent; `rel="alternate"` just gives the ones that look for it
a second path.