How HTTP Works

Request header

> Sec-Fetch-Dest: document

Sec-Fetch-Dest Header: All Values Explained

Sec-Fetch-Dest tells the server where a response will be used: document, iframe, image, script, empty. Full value list and server-side uses.

Reviewed 3 min readintermediate3 sourcesTry itMarkdown
Direction
Request
Category
Security
Spec
W3C Fetch Metadata
JS can set it
No: forbidden header name
On this page

TL;DR: Sec-Fetch-Dest tells your server what the browser will do with the response: render it as a document, put it in an iframe, use it as an image, run it as a script, or hand it to JavaScript (empty). It lets you refuse, for example, to serve a JSON endpoint to an <img> tag or a private page to an <iframe> on another site.

Example

GET /avatar.png HTTP/1.1
Host: example.com
Sec-Fetch-Dest: image
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: cross-site

This is a cross-site <img>: another site is hotlinking your image. The header is a structured-field token (section 2.1 of the W3C Fetch Metadata spec) and a forbidden request header, so scripts cannot set it.

Values

From MDN’s current list, with what produces each:

ValueSource
audio<audio>
audioworkletaudioWorklet.addModule()
documentA top-level navigation
embed<embed>
emptyfetch(), XMLHttpRequest, navigator.sendBeacon(), EventSource, WebSocket and other requests with no specific destination
fencedframeThe Fenced Frame API (Chromium only)
fontCSS @font-face
frame<frame>
iframe<iframe>
image<img>, SVG <image>, CSS background-image and similar
jsonimport ... with { type: "json" }
manifest<link rel="manifest">
object<object>
paintworkletCSS.paintWorklet.addModule()
reportCSP and other violation reports
script<script>, importScripts()
serviceworkernavigator.serviceWorker.register()
sharedworkernew SharedWorker()
style<link rel="stylesheet">, CSS @import, import ... with { type: "css" }
textimport ... with { type: "text" }
track<track>
video<video>
webidentityFedCM identity endpoints
workernew Worker()
xsltXSLT transforms

The list follows the Fetch Standard’s request destinations and grows with the platform, so write server rules as an allow-list for the destinations you expect rather than a deny-list of known-bad ones.

Practical uses

  • Refuse to be framed or embedded. A cross-site request with Sec-Fetch-Dest: iframe, frame, embed or object to a page that has no business being framed can get a 403. frame-ancestors in Content-Security-Policy is the browser-enforced way to do it, and it covers browsers that do not send this header.
  • Stop JSON endpoints being loaded as scripts. An API that only serves empty destinations should reject script, which is the shape of old JSONP-style cross-site data theft.
  • Cut hotlinking. Reject image, video or audio destinations when Sec-Fetch-Site is cross-site and send an alternative.
  • Separate navigations from XHR. document is a person opening a page, empty is code calling an API. Same URL, different handling, with Vary: Sec-Fetch-Dest if anything is cached.
# Serve downloads only to navigations and same-site code, never to cross-site embeds
map "$http_sec_fetch_site:$http_sec_fetch_dest" $block_embed {
    default                          0;
    "~^cross-site:(iframe|frame|embed|object)$"  1;
}

Then if ($block_embed) { return 403; } in the relevant location. The full policy that combines Dest with Site and Mode is on the Sec-Fetch-Site page.

Browser support

Chrome and Edge 80, Firefox 90, Safari 16.4. Sent only to potentially trustworthy URLs (HTTPS and localhost). Absent for curl and server-side clients.

Frequently asked questions

What does Sec-Fetch-Dest: empty mean?

empty is the token for requests with no specific destination, which is what fetch(), XMLHttpRequest, navigator.sendBeacon(), EventSource and WebSocket produce. The Fetch Standard represents this destination as the empty string, and the Fetch Metadata spec maps it to the token empty because a structured-field token cannot be blank.

How do I stop my files being embedded in iframes using Sec-Fetch-Dest?

Reject requests with Sec-Fetch-Dest of iframe, frame, embed or object when they come from another site. For a response-side control that browsers enforce for you, use Content-Security-Policy frame-ancestors; the Sec-Fetch-Dest check is useful when you want to refuse to serve the bytes at all.

Is Sec-Fetch-Dest sent in Safari?

Yes, since Safari 16.4. Chrome and Edge have sent it since 80 and Firefox since 90. The fencedframe value is only available in Chromium, and non-browser clients send none of the Sec-Fetch headers.

Can I serve different content based on Sec-Fetch-Dest?

You can, for example returning an app shell for document and JSON for empty at the same URL, but you must add Vary: Sec-Fetch-Dest to the response or a shared cache will hand the wrong representation to the next client. Separate URLs are simpler to reason about.

Sources

  1. MDN Web Docs: Sec-Fetch-Destdeveloper.mozilla.org
  2. W3C Fetch Metadata Request Headers, section 2.1w3c.github.io
  3. Fetch Standard: request destinationfetch.spec.whatwg.org

Keep going

Browse /search