# Set the Vary: Accept header

Without `Vary: Accept`, CDNs and browser caches will happily serve the wrong representation to the wrong audience.

`Vary: Accept` is the single most-forgotten piece of content negotiation.
Without it, any cache between you and your reader — a CDN, a browser, a
corporate proxy — can serve the HTML version of a page to an agent, or
the Markdown version to a human, depending only on whoever asked first.

## What it does

`Vary` tells downstream caches: *the representation you just cached
depends on the value of this request header*. Cache entries are keyed
by the URL **plus** the listed headers.

```http
HTTP/1.1 200 OK
Content-Type: text/markdown; charset=utf-8
Vary: Accept
Cache-Control: public, max-age=300
```

Now the CDN stores two separate cache entries for `/article`: one for
`Accept: text/markdown`, another for `Accept: text/html`. Each reader
gets the right bytes.

## What it looks like when you forget

An agent requests your article, gets Markdown, and the CDN caches it
keyed on URL alone. Ten seconds later a browser requests the same URL —
and the CDN happily returns a `text/markdown` blob that renders as raw
text in the browser. Or the reverse: the browser primes the cache with
HTML, the agent gets a wall of `<div>` soup.

## Gotchas

- `Vary: *` disables caching entirely. You almost never want this.
- `Vary: Accept` is **case-insensitive** as a header name, but the
  values you pass in `Accept` are matched literally by most CDNs. That's
  why normalizing `Accept` on your origin is important (see the
  [Accept parsing guide](/guides/accept-parsing)).
- If you also vary by `Accept-Encoding`, list them together:
  `Vary: Accept, Accept-Encoding`.

## Verify it

```bash
curl -sI -H "Accept: text/markdown" https://yoursite.com/article | grep -i vary
```

You should see `Vary: Accept` (possibly alongside other values). If
it's missing, your CDN is a timebomb.