Request header
> Accept: text/html,application/json;q=0.9Accept Header
Learn how the Accept header tells servers which content types (JSON, HTML, XML) your client can handle. Master content negotiation and quality values.
- Direction
- Request
- Category
- Content negotiation
- Spec
- RFC 9110 §12.5.1
- JS can set it
- Yes
- CORS-safelisted
- Yes
On this page
TL;DR:
Acceptis a request header that tells the server which response formats you can handle, such asAccept: application/json. Rank alternatives with q-values (text/html, application/json;q=0.9). It’s a request, not a contract: the server may send something else or a 406, so check the response’sContent-Typebefore you parse it.
What is Accept?
Accept is how a client asks for a response format. Content-Type labels the format that was actually sent. A request with no Accept header means the client will take any media type.
The two headers point in opposite directions. A POST can send a JSON body and ask for a plain-text reply:
Content-Type: application/json
Accept: text/plain
Accept only affects the response. The server still parses the request body according to its Content-Type.
How Accept Works
Here’s a request (the examples on this page are trimmed):
GET /report HTTP/1.1
Host: example.com
Accept: application/json, text/csv;q=0.8
The server should pick JSON, or CSV if it can’t produce JSON. If it has nothing acceptable, it can either return 406 or ignore the header and send a default. RFC 9110 §12.5.1 allows both.
Syntax and Quality Values
Accept: text/html, application/json;q=0.9, */*;q=0.1
A missing q means 1, and q=0 means “not acceptable”. Values go from 0 to 1 with at most three decimal places. Order doesn’t matter: two entries with the same q-value are equally preferred, whichever comes first.
When a representation matches several entries, the most specific one sets its quality. Here plain text gets quality zero, while every other text type gets one:
Accept: text/*;q=1, text/plain;q=0
Common Examples
Request JSON with a plain-text fallback:
curl -i -H 'Accept: application/json, text/plain;q=0.5' https://example.com/report
Point it at an endpoint that actually implements both formats; asking for JSON won’t make a server that only speaks HTML produce it.
Content Type Categories
Media types take the form type/subtype. Parameters such as charset can narrow a match further. q is the exception: it states your preference and says nothing about the content.
| Value | Requested representation |
|---|---|
application/json | JSON |
text/html | HTML |
text/csv | CSV |
image/png | PNG image |
If a server returns JSON labelled text/html, that’s a server bug, and clients will treat it as HTML. Trust the response’s Content-Type, not the URL’s file extension.
Wildcards
image/* matches any image subtype, and */* matches anything. Adding */*;q=0.1 gives the server a low-priority fallback. Leaving it out won’t stop a server that ignores Accept anyway.
Accept: image/png, image/*;q=0.8, */*;q=0.1
PNG gets quality 1, any other image type 0.8, and anything else 0.1. The server picks the best of the formats it can actually produce.
Real-World Scenarios
If one URL serves both JSON and HTML, add Vary: Accept to the negotiated responses so caches key on that request header. See Vary.
Skip it and a shared cache may hand the last visitor’s HTML to an API client that asked for JSON. For the /status route below, request both formats it implements:
curl -i -H 'Accept: application/json' https://example.com/status
curl -i -H 'Accept: text/plain' https://example.com/status
Both responses should list Accept in Vary, including the one in the server’s default format.
Server Response Strategies
Parse the header with a negotiation library. A substring check like accept.includes('application/json') gets q=0, wildcards and a missing header wrong.
In Express, res.format() handles routes with several serializers. Drop this into an existing app:
app.get('/status', (req, res) => {
res.vary('Accept')
res.format({
'application/json': () => res.json({ status: 'ready' }),
'text/plain': () => res.send('ready\n'),
default: () => res.status(406).end()
})
})
Make the fallback explicit. When the request has no Accept header, res.format() runs the first handler; that’s your app’s default, not something the client asked for.
Getting Accept right
For finer control, req.accepts() picks from the formats your route actually implements:
app.get('/report', (req, res) => {
res.vary('Accept')
const format = req.accepts(['application/json', 'text/plain'])
if (format === 'application/json') return res.json({ status: 'ready' })
if (format === 'text/plain') return res.type('text/plain').send('ready\n')
return res.status(406).end()
})
Common Patterns
On the client, send the format you want, then check the response Content-Type before decoding. Accept asks; it doesn’t validate what comes back.
In browser JavaScript, check the status first. Error responses often come in a different media type from successful ones:
const response = await fetch('/report', {
headers: { Accept: 'application/json' }
})
if (!response.ok) throw new Error(`HTTP ${response.status}`)
const type = response.headers.get('Content-Type')?.split(';')[0].trim()
if (type !== 'application/json') throw new Error(`Unexpected type: ${type}`)
const report = await response.json()
This client accepts only application/json on purpose. Add other media types when the API contract says they’re supported.
Browser Defaults
Browsers send different values for page navigations, images and other requests, so there’s no single browser default to copy into an API client. To see what was sent, open Network → request → Request Headers for the request you’re debugging. MDN lists example values by request context.
Testing Accept Headers
Test the rejection paths, not only the happy one. The last command removes the header that curl sends by default:
curl -i -H 'Accept: application/json;q=0, text/plain;q=1' https://example.com/report
curl -i -H 'Accept: application/pdf' https://example.com/report
curl -i -H 'Accept:' https://example.com/report
For each, look at the status, Content-Type and Vary together.
Related Headers
Frequently asked questions
What is the Accept header?
Accept tells the server which content types the client can handle. The server uses this for content negotiation to choose the best response format.
How do I request JSON from an API?
Send Accept: application/json. The server should return JSON if it supports it. Some APIs require this header; others default to JSON.
What does the quality value (q) mean?
Quality values indicate preference from 0 to 1. Accept: text/html, application/json;q=0.9 prefers HTML but accepts JSON. Higher q means higher preference.
What happens if the server cannot match Accept?
The server can return 406 Not Acceptable, or ignore Accept and send its default format. Both are allowed, so check the status and Content-Type of what comes back.
Sources
Related
Content Negotiation
Content negotiation lets one URL serve different formats, languages or encodings based on Accept headers. See q-values, Vary, 406 and the caching traps.
Accept-Language Header
Learn how the Accept-Language header tells servers which languages your client prefers for localized content. Understand language tags and quality values.
Expect Header: 100-continue, curl Delays and 417
Expect: 100-continue asks the server to approve a request before the body is sent. Why curl adds it past 1 MB, the 1s delay, -H "Expect:", and 417.
Forwarded
Learn how the Forwarded header preserves original client information (IP, protocol, host) that would otherwise be lost when requests pass through proxies.