| [ Web Proxy ] |
| Viewing: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Fetch_metadata | [Back] [Original] |
Get to know MDN better
Fetch metadata is the term for a group of HTTP request headers that give the server information about the context in which the request is being made.
Among other things, fetch metadata allows the server to know:
Whether the request represents a navigation between documents, or a request for a subresource, or was explicitly made from JavaScript, for example using the fetch() API.
The relationship between the requester of the resource and the resource being requested: whether they are same-origin, or same-site, or from completely different sites.
By using the information in these headers to allow or deny specific requests, a server can implement a defense against cross-origin attacks such as cross-site request forgeries (CSRF) and various cross-site leaks.
The Fetch metadata specification defines four fetch metadata headers:
Like all Sec- prefixed headers, these are forbidden request headers, which means they can't be set or modified by the website's front-end code.
This header indicates the destination of the request. This attribute is defined in the Fetch API, where it is exposed as the Request.destination property.
We could think of it, roughly, as the way the returned resource would be used.
For most replaced elements, the value of the header names the element that this resource will be used for, such as iframe, object, audio, or video. A value of image indicates that the resource will be used as an image referenced by a replaced element such as an HTML <img> element, a CSS background-image property, an SVG <image>, or any other place in the web platform that use images loaded from subresources.
Some other interesting destination values include:
documentThe request is for a new document that is the target of a top-level navigation (for example, the user clicking a link in the page or submitting a form).
scriptThe resource will be used as a script loaded from an HTML <script> element or a call to importScripts() in a web worker.
More specific values are used to indicate other places where the resource is used as a script, such as worklets (audioworklet and paintworklet) and workers (sharedworker, serviceworker, and worker).
emptyThe request does not have a defined destination: among other possible causes, this is the value given if the request is the result of a fetch() call.
For the complete set of possible values, see the reference page for this header.
This header indicates the mode of the request. Like destination, the mode is defined in the Fetch API, where it is exposed as the Request.mode property.
Its most commonly used values are:
navigateThe request represents a navigation between documents (for example, the user clicking a link).
no-corsThe request was made in no-cors mode.
This means that it is allowed cross-origin without the server sending the appropriate CORS headers, with the restriction that the response can't be accessed by JavaScript running in the client (it is opaque).
This is the default mode for pages that load subresources such as images, fonts, scripts, and stylesheets, and explains why a different site is by default allowed to use your site's subresources, even if you haven't configured CORS to allow it.
corsIf the request is cross-origin, then the server must respond with the appropriate CORS headers, or the request will fail. If the server does respond with the appropriate CORS headers, then the response body and certain headers will be made available to the caller.
This is most often found for cross-origin requests made from JavaScript using the Fetch API, when the requester needs access to the returned resource (for example, a fetch call to retrieve some JSON from the server).
same-originThe request is only allowed if the requester is same-origin with the resource being requested.
This header indicates the relationship between the origin of the resource being requested and the origin of the requester of the resource.
It indicates whether the requester is from:
For example, if a user clicks a link in a page at https://books.example.org/authors, the browser makes a request to fetch the document specified in the link target. The following table shows values of the associated Sec-Fetch-Site header for different link target values:
| Link target | Sec-Fetch-Site value |
|---|---|
https://books.example.org/titles |
same-origin |
https://login.example.org/ |
same-site |
https://books.example.com/titles |
cross-site |
Similar mappings apply for other HTTP requests, such as:
action attribute of a <form> element.fetch() API.The Sec-Fetch-Site header may also have the value none for requests that don't have a site as the requester, including, for example, requests made when the user types a URL into the browser's address bar or clicks a bookmark. The specification calls these directly user-initiated requests.
This header is included only if the request was initiated by a user action (such as a click on a link), and if included, always has the value ?1.
Fetch metadata is especially useful as a defense against cross-origin attacks. These attacks typically target a user who has an account with a legitimate site, and is signed into this site. The attacker creates a website that makes a cross-origin request to the legitimate site, and then tricks the user into executing that request.
Note: We use the term cross-origin attack in this guide, although many attacks are conventionally called cross-site attacks.
An origin is a more restrictive concept than a site. In particular, a site includes a domain's subdomains, and an origin does not: so https://example.org and https://login.example.org are the same site, but different origins.
This means that while all cross-site attacks are cross-origin attacks, some cross-origin attacks are not cross-site attacks. For example, if an attacker gains control of a subdomain of a site, then they can attack the site using cross-origin, same-site requests. To include these attacks, we use the more restrictive term.
For example, the attacker's site might contain a <form> element that submits to the legitimate site. For some cross-origin attacks, no user interaction is needed at all: the attacker's page can just execute a fetch() request to the legitimate site on page load, and then the user only has to open the attacker's page for the cross-origin request to be executed.
Because the request came from the user's browser, it will include any cookies set for the user by the legitimate site, including cookies that the legitimate site uses to identify users. The request will therefore be given the privileges for that user.
We can distinguish two sorts of cross-origin attack:
Cross-site request forgery (CSRF) attacks: in these attacks, the cross-origin request performs some consequential action in the legitimate server, using parameters supplied by the attacker. For example, the request asks the server to transfer money from the target user's account into the attacker's account.
Cross-site leaks: in these attacks, the attacker uses the request to gain information about the user's relationship with the target site, often through side channels such as error events.
Most websites will want to deny some cross-origin requests while allowing others: for example, if you deny all cross-origin requests, no one will be able to navigate to your site from a different site!
Using fetch metadata, a server can construct a policy for allowing or denying cross-origin requests based on the details of their context.
A common type of policy is called a resource isolation policy. When the server receives a request, it examines the request's fetch metadata headers to allow only:
For example, the following Express code allows only same-origin requests, directly user-initiated requests, and navigations.
function isAllowed(req) {
// Allow same-origin requests
// Allow directly user-initiated requests (from bookmarks, address bar etc.)
const secFetchSite = req.headers["sec-fetch-site"];
if (secFetchSite === "same-origin" || secFetchSite === "none") {
return true;
}
// Allow cross-site navigations, such as clicking links
const secFetchMode = req.headers["sec-fetch-mode"];
if (secFetchMode === "navigate" && req.method === "GET") {
return true;
}
// Deny everything else
return false;
}
app.get("/admin", (req, res) => {
res.setHeader("Vary", "sec-fetch-site, sec-fetch-mode");
if (isAllowed(req)) {
// Respond with the admin page if the user is admin
getAdminPage(req, res);
} else {
res.status(403).send("Forbidden");
}
});
Note that it also sends the Vary response header. This ensures that if the response is cached, the cached response will only be given to requests with the same values for the Fetch metadata headers we are using.
The Resource Isolation Policy page provides more sample code for a resource isolation policy.
This page was last modified on Apr 6, 2026 by MDN contributors.
Reason: CORS disabledReason: CORS header 'Access-Control-Allow-Origin' does not match 'xyz'Reason: CORS header 'Access-Control-Allow-Origin' missingReason: CORS header 'Origin' cannot be addedReason: CORS preflight channel did not succeedReason: CORS request did not succeedReason: CORS request external redirect not allowedReason: CORS request not HTTPReason: Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*'Reason: Did not find method in CORS header 'Access-Control-Allow-Methods'Reason: expected 'true' in CORS header 'Access-Control-Allow-Credentials'Reason: invalid token 'xyz' in CORS header 'Access-Control-Allow-Headers'Reason: invalid token 'xyz' in CORS header 'Access-Control-Allow-Methods'Reason: missing token 'xyz' in CORS header 'Access-Control-Allow-Headers' from CORS preflight channelReason: Multiple CORS header 'Access-Control-Allow-Origin' not allowedAcceptAccept-CHAccept-EncodingAccept-LanguageAccept-PatchAccept-PostAccept-RangesAccess-Control-Allow-CredentialsAccess-Control-Allow-HeadersAccess-Control-Allow-MethodsAccess-Control-Allow-OriginAccess-Control-Expose-HeadersAccess-Control-Max-AgeAccess-Control-Request-HeadersAccess-Control-Request-MethodActivate-Storage-AccessAgeAllowAlt-SvcAlt-UsedAttribution-Reporting-EligibleAttribution-Reporting-Register-SourceAttribution-Reporting-Register-TriggerAuthorizationAvailable-DictionaryCache-ControlClear-Site-DataConnectionContent-DigestContent-DispositionContent-DPRContent-EncodingContent-LanguageContent-LengthContent-LocationContent-RangeContent-Security-PolicyContent-Security-Policy-Report-OnlyContent-TypeCookieCritical-CHCross-Origin-Embedder-PolicyCross-Origin-Embedder-Policy-Report-OnlyCross-Origin-Opener-PolicyCross-Origin-Resource-PolicyDateDevice-MemoryDictionary-IDDNTDownlinkDPREarly-DataECTETagExpectExpect-CTExpiresForwardedFromHostIdempotency-KeyIf-MatchIf-Modified-SinceIf-None-MatchIf-RangeIf-Unmodified-SinceIntegrity-PolicyIntegrity-Policy-Report-OnlyKeep-AliveLast-ModifiedLinkLocationMax-ForwardsNELNo-Vary-SearchObserve-Browsing-TopicsOriginOrigin-Agent-ClusterPermissions-PolicyPermissions-Policy-Report-OnlyPragmaPreferPreference-AppliedPriorityProxy-AuthenticateProxy-AuthorizationRangeRefererReferrer-PolicyRefreshReport-ToReporting-EndpointsRepr-DigestRetry-AfterRTTSave-DataSec-Browsing-TopicsSec-CH-Device-MemorySec-CH-DPRSec-CH-Prefers-Color-SchemeSec-CH-Prefers-Reduced-MotionSec-CH-Prefers-Reduced-TransparencySec-CH-UASec-CH-UA-ArchSec-CH-UA-BitnessSec-CH-UA-Form-FactorsSec-CH-UA-Full-VersionSec-CH-UA-Full-Version-ListSec-CH-UA-MobileSec-CH-UA-ModelSec-CH-UA-PlatformSec-CH-UA-Platform-VersionSec-CH-UA-WoW64Sec-CH-Viewport-HeightSec-CH-Viewport-WidthSec-CH-WidthSec-Fetch-DestSec-Fetch-ModeSec-Fetch-SiteSec-Fetch-Storage-AccessSec-Fetch-UserSec-GPCSec-Private-State-TokenSec-Private-State-Token-Crypto-VersionSec-Private-State-Token-LifetimeSec-PurposeSec-Redemption-RecordSec-Speculation-TagsSec-WebSocket-AcceptSec-WebSocket-ExtensionsSec-WebSocket-KeySec-WebSocket-ProtocolSec-WebSocket-VersionServerServer-TimingService-WorkerService-Worker-AllowedService-Worker-Navigation-PreloadSet-CookieSet-LoginSourceMapSpeculation-RulesStrict-Transport-SecuritySupports-Loading-ModeTETiming-Allow-OriginTkTrailerTransfer-EncodingUpgradeUpgrade-Insecure-RequestsUse-As-DictionaryUser-AgentVaryViaViewport-WidthWant-Content-DigestWant-Repr-DigestWarningWidthWWW-AuthenticateX-Content-Type-OptionsX-DNS-Prefetch-ControlX-Forwarded-ForX-Forwarded-HostX-Forwarded-ProtoX-Frame-OptionsX-Permitted-Cross-Domain-PoliciesX-Powered-ByX-Robots-TagX-XSS-Protection100 Continue101 Switching Protocols102 Processing103 Early Hints200 OK201 Created202 Accepted203 Non-Authoritative Information204 No Content205 Reset Content206 Partial Content207 Multi-Status208 Already Reported226 IM Used300 Multiple Choices301 Moved Permanently302 Found303 See Other304 Not Modified307 Temporary Redirect308 Permanent Redirect400 Bad Request401 Unauthorized402 Payment Required403 Forbidden404 Not Found405 Method Not Allowed406 Not Acceptable407 Proxy Authentication Required408 Request Timeout409 Conflict410 Gone411 Length Required412 Precondition Failed413 Content Too Large414 URI Too Long415 Unsupported Media Type416 Range Not Satisfiable417 Expectation Failed418 I'm a teapot421 Misdirected Request422 Unprocessable Content423 Locked424 Failed Dependency425 Too Early426 Upgrade Required428 Precondition Required429 Too Many Requests431 Request Header Fields Too Large451 Unavailable For Legal Reasons500 Internal Server Error501 Not Implemented502 Bad Gateway503 Service Unavailable504 Gateway Timeout505 HTTP Version Not Supported506 Variant Also Negotiates507 Insufficient Storage508 Loop Detected510 Not Extended511 Network Authentication Requiredbase-uriblock-all-mixed-contentchild-srcconnect-srcdefault-srcfenced-frame-srcfont-srcform-actionframe-ancestorsframe-srcimg-srcmanifest-srcmedia-srcobject-srcprefetch-srcreport-toreport-urirequire-trusted-types-forsandboxscript-srcscript-src-attrscript-src-elemstyle-srcstyle-src-attrstyle-src-elemtrusted-typesupgrade-insecure-requestsworker-srcaccelerometerambient-light-sensoraria-notifyattribution-reportingautoplaybluetoothbrowsing-topicscameracaptured-surface-controlch-ua-high-entropy-valuescompute-pressurecross-origin-isolateddeferred-fetchdeferred-fetch-minimaldisplay-captureencrypted-mediafullscreengamepadgeolocationgyroscopehididentity-credentials-getidle-detectionlanguage-detectorlanguage-modellocal-fontslocal-networklocal-network-accessloopback-networkmagnetometermicrophonemidion-device-speech-recognitionotp-credentialspaymentpicture-in-pictureprivate-state-token-issuanceprivate-state-token-redemptionpublickey-credentials-createpublickey-credentials-getscreen-wake-lockserialspeaker-selectionstorage-accesssummarizertranslatorusbweb-sharewindow-managementxr-spatial-trackingYour blueprint for a better internet.
Portions of this content are 19982026 by individual mozilla.org contributors. Content available under a Creative Commons license.
| Web Proxy Viewer | New URL | Original Page |