GuidesUNDERSTAND
Sec-Fetch-Mode and Fetch Metadata
Fetch Metadata request headers provide servers with contextual details about why and where a browser initiated an HTTP request. The browser automatically sets Sec-Fetch-Mode alongside other metadata headers to declare the execution mode of the call, such as standard navigation or cross-origin fetch. Because the user agent sets these headers directly, servers can evaluate the origin and destination context before returning sensitive resources.
The four fetch metadata headers
Browsers automatically attach fetch metadata request headers to outgoing network calls. Because these headers use the Sec- prefix, they are forbidden request headers that JavaScript cannot set or alter, so servers can trust that the browser generated them.
| Header | What it tells the server | Example value |
|---|---|---|
| Sec-Fetch-Mode | The mode of the request, mirroring Request.mode | cors |
| Sec-Fetch-Site | The relationship between the initiator and the target | cross-site |
| Sec-Fetch-Dest | Where the response will be used | document |
| Sec-Fetch-User | Present only on user-activated navigations | ?1 |
The values you will see
The values reflect both the networking mode initiated by the browser and the relationship between the requesting origin and target destination. While Sec-Fetch-Mode, Sec-Fetch-Site, and Sec-Fetch-Dest have baseline browser support since March 2023, Sec-Fetch-User is not baseline because Safari does not send it.
| Header | Values | Meaning |
|---|---|---|
| Sec-Fetch-Mode | cors, no-cors, navigate, same-origin, websocket | cors marks a CORS protocol request such as a cross-origin fetch; navigate marks a top-level navigation; no-cors marks legacy loads such as images and scripts; websocket marks a WebSocket handshake |
| Sec-Fetch-Site | same-origin, same-site, cross-site, none | same-origin matches scheme, host, and port; same-site covers sibling subdomains on the same site; cross-site is a different site entirely; none means the user caused it directly, such as typing a URL or opening a bookmark |
How servers use fetch metadata
Servers use these headers to implement a resource isolation policy that rejects unexpected cross-site requests with a 403 response. An Express-style middleware can inspect state-changing methods, specifically anything other than GET, HEAD, or OPTIONS, and reject incoming traffic when Sec-Fetch-Site is cross-site. Requests marked as same-origin, same-site, or none pass through, while missing headers fall back to traditional CSRF defenses rather than triggering an outright rejection.
// Reject cross-site state changes before any route logic runs
app.use((req, res, next) => {
const site = req.get('sec-fetch-site');
// Older browsers may omit the header: fall back to CSRF tokens
if (site === undefined) return next();
const trusted = site === 'same-origin' || site === 'same-site' || site === 'none';
const readOnly = ['GET', 'HEAD', 'OPTIONS'].includes(req.method);
if (!trusted && !readOnly) {
return res.status(403).send('Cross-site state changes are not allowed');
}
next();
});This pattern mitigates cross-site request forgery, cross-site script inclusion, cross-origin information leaks, and timing attacks. Because older browsers may omit these headers entirely and Safari omits Sec-Fetch-User, servers must tolerate missing headers and ignore unrecognized values instead of assuming automated or malicious behavior.
Fetch metadata is not CORS
Fetch metadata headers provide informational context to the destination server, but they do not participate in browser-side CORS enforcement. They do not grant cross-origin read access, and they do not replace Access-Control-Allow-Origin. Even if an incoming request provides valid fetch metadata headers, the browser will still withhold the response from client-side scripts unless the server returns matching CORS response headers.
The browser's decision to release response data depends entirely on the presence and correctness of CORS response headers. If an API is under your direct control, configure your server to return appropriate CORS headers. For third-party public APIs that you cannot modify, an intermediary like the cors.dev proxy can be used to attach the necessary headers for supported public endpoints.
Good questions.
Can JavaScript change or fake Sec-Fetch-Mode?
No. The Sec- prefix designates it as a forbidden request header. Browsers prevent client-side JavaScript from modifying, deleting, or spoofing forbidden request headers, ensuring that destination servers receive values generated exclusively by the browser.
Does Sec-Fetch-Site replace CSRF tokens?
It does not fully replace CSRF tokens. While it provides a strong primary filter against cross-site requests, older browsers may not send fetch metadata headers. Servers must treat a missing Sec-Fetch-Site header as unknown and maintain CSRF tokens as a fallback defense.
Do these headers affect CORS errors?
No. Fetch metadata headers are outbound signals sent from the browser to help the server detect request context. They play no role in the browser's client-side CORS verification checks, which evaluate only the server's Access-Control-Allow-Origin response headers.