GuidesERR_BLOCKED_BY_RESPONSE
Blocked by response: X-Frame-Options, CSP, CORP and COEP fixes
net::ERR_BLOCKED_BY_RESPONSE means the server answered, but one of 4 response headers forbids your page from using the answer: X-Frame-Options or CSP frame-ancestors for an iframe, Cross-Origin-Resource-Policy for an image or script, or your own page's Cross-Origin-Embedder-Policy. Fix it on the server that sends the header; if you don't own that site, you can't embed it and have to show its content another way. We ran 32 cases in Chromium 153, Firefox 155 and WebKit 26.6 on 26 October 2026 and recorded what each engine logs.
What the error means
Chromium's source defines error -27 as a request that "failed because the response was delivered along with requirements which are not met", naming the X-Frame-Options and CSP ancestor checks and Cross-Origin-Resource-Policy. The server did answer: in our test the blocked frame arrived with status 200 and the browser threw it away.
Frames get the plain code. Images, scripts and no-cors fetches blocked by CORP get a suffix: .NotSameOrigin, .NotSameSite, or .NotSameOriginAfterDefaultedToSameOriginByCoep when your page's COEP forced the check. Inside a blocked frame, Chrome's error page says <host> refused to connect., Firefox says Firefox Can't Open This Page and suggests opening it in a new window, and WebKit leaves the frame empty.
Three lookalikes have other causes:
net::ERR_BLOCKED_BY_CSP: your own page's CSP, for exampleframe-src 'none', blocked the frame.net::ERR_BLOCKED_BY_ORB: animgorscripttag points at JSON or HTML from another origin.net::ERR_BLOCKED_BY_CLIENT: the browser or an extension chose to block the request.
Which header blocked it
| Header and value | What it blocks | Chromium 153 error | Fix |
|---|---|---|---|
| X-Frame-Options: DENY | Every frame, your own origin included | net::ERR_BLOCKED_BY_RESPONSE; console: Refused to display '...' in a frame because it set 'X-Frame-Options' to 'deny'. | Replace with frame-ancestors listing the origins you allow |
| X-Frame-Options: SAMEORIGIN | Frames on other origins | net::ERR_BLOCKED_BY_RESPONSE; console: same line, set to 'sameorigin'. | frame-ancestors 'self' plus the origins you allow |
| X-Frame-Options: ALLOW-FROM origin | Nothing: all 3 engines ignore the header | None, the frame loads; console: Invalid 'X-Frame-Options' header ... The header will be ignored. | Replace with frame-ancestors |
| Content-Security-Policy: frame-ancestors 'none', or a list without your origin | Frames on every origin not listed | net::ERR_BLOCKED_BY_RESPONSE; console: Framing '...' violates the following Content Security Policy directive | Add the embedding origin to the list |
| frame-ancestors in a meta tag | Nothing: ignored in all 3 engines | None, the frame loads; console: ... is ignored when delivered via a <meta> element. | Send it as an HTTP response header |
| Cross-Origin-Resource-Policy: same-origin | img, script and no-cors fetch from other origins, other ports included | net::ERR_BLOCKED_BY_RESPONSE.NotSameOrigin | Cross-Origin-Resource-Policy: cross-origin |
| Cross-Origin-Resource-Policy: same-site | The same loads from other sites | net::ERR_BLOCKED_BY_RESPONSE.NotSameSite | cross-origin, or serve both from one site |
| Your page sends Cross-Origin-Embedder-Policy: require-corp, the file has no CORP | Cross-origin img and script without CORP or CORS | net::ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoep | CORP cross-origin on the file, crossorigin plus CORS, or COEP credentialless |
| Your page sends COEP require-corp, the framed page lacks COEP and CORP | Cross-origin iframes | net::ERR_BLOCKED_BY_RESPONSE; no console line, Issues panel only | The framed page sends COEP and Cross-Origin-Resource-Policy: cross-origin |
ALLOW-FROM protects nothing: all 3 engines ignored X-Frame-Options: ALLOW-FROM http://127.0.0.1:8001 and loaded the frame, and MDN calls the directive obsolete. X-Frame-Options has no allow-list, so frame-ancestors is the way to allow named sites. When a response carried both X-Frame-Options: DENY and a frame-ancestors list with our origin, all 3 engines loaded the frame: frame-ancestors wins. It only works as an HTTP header; all 3 engines ignored it in a meta tag.
Ports count for same-origin. A page on http://localhost:8001 could not load an image from http://localhost:8002 sent with Cross-Origin-Resource-Policy: same-origin in any engine, while same-site loaded, because a site ignores the port. That is the usual local setup of a frontend and an API on two ports, and Express with helmet() 8.3.0 sends Cross-Origin-Resource-Policy: same-origin, X-Frame-Options: SAMEORIGIN and frame-ancestors 'self' by default.
What Firefox and Safari log
- X-Frame-Options: Firefox 155 logs
The loading of "<url>" in a frame is denied by "X-Frame-Options" directive set to "deny".WebKit 26.6 logsRefused to display '<url>' in a frame because it set 'X-Frame-Options' to 'DENY'. - frame-ancestors: Firefox logs
Content-Security-Policy: The page's settings blocked the loading of a resource (frame-ancestors)followed by the directive. WebKit logsRefused to load <url> because it does not appear in the frame-ancestors directive of the Content Security Policy. - CORP: Firefox logs
The resource at "<url>" was blocked due to its Cross-Origin-Resource-Policy header (or lack thereof).WebKit logsCancelled load to <url> because it violates the resource's Cross-Origin-Resource-Policy response header. - COEP iframe: Chromium and Firefox print nothing in the Console. Chrome lists it under Issues, and its Network tab shows
(blocked:COEP-framed resource needs COEP header)when the frame sends CORP without COEP. WebKit logs its CORP line orRefused to display '<url>' in a frame because of Cross-Origin-Embedder-Policy.
What JavaScript can see
The iframe load event fired for frames blocked by X-Frame-Options and frame-ancestors in all 3 engines, and reading iframe.contentWindow.location.href threw SecurityError whether the cross-origin frame loaded or not, so the embedding page can't tell the difference. If you control the framed page, have it postMessage the parent on load and treat silence as blocked: in our test the message arrived every time the frame loaded and never when it was blocked. For images onerror fires with naturalWidth 0, and a no-cors fetch() rejects with the generic TypeError; neither says why.
Fix it on the server that sends the header
- Frames
on the framed site, send
Content-Security-Policy: frame-ancestors 'self' https://app.example.com, listing every origin allowed to embed it. Keep or dropX-Frame-Options;frame-ancestorsoverrides it. - Images, scripts and files
on the server that serves them, send
Cross-Origin-Resource-Policy: cross-origin, orsame-sitewhen both origins share a site. CORP does not apply to CORS requests: afetch()in cors mode to a file withAccess-Control-Allow-Origin: *and CORPsame-originreturned 200 in all 3 engines. - Pages with COEP
have the files send CORP
cross-origin, or addcrossorigin="anonymous"to the tag and sendAccess-Control-Allow-Originfrom the file server, or switch toCross-Origin-Embedder-Policy: credentialless, which Chromium and Firefox apply and WebKit 26.6 did not. A cross-origin iframe still needs its own COEP header plus CORPcross-origin;credentiallessdid not relax that. The Cross-Origin-Opener-Policy guide covers the isolation side.
import express from 'express';
import helmet from 'helmet';
const app = express();
// helmet() 8.3 defaults to X-Frame-Options: SAMEORIGIN, frame-ancestors 'self' and CORP same-origin
app.use(
helmet({
xFrameOptions: false,
contentSecurityPolicy: {
directives: { frameAncestors: ["'self'", 'https://app.example.com'] },
},
crossOriginResourcePolicy: { policy: 'cross-origin' },
}),
);
app.get('/', (req, res) => res.send('<h1>Embeddable page</h1>'));
app.listen(3000, async () => {
const response = await fetch('http://localhost:3000/');
console.log({
'x-frame-options': response.headers.get('x-frame-options'),
'frame-ancestors': response.headers.get('content-security-policy').match(/frame-ancestors[^;]*/)[0],
'cross-origin-resource-policy': response.headers.get('cross-origin-resource-policy'),
});
});# _headers in the publish directory (Netlify, Cloudflare Pages)
/embed/*
Content-Security-Policy: frame-ancestors 'self' https://app.example.com
/images/*
Cross-Origin-Resource-Policy: cross-originWhen you don't own the site
Without control of that server you can't embed the page. A proxy that strips X-Frame-Options or CSP isn't a fix: it breaks logins and cookies, and it is the pattern clickjacking uses. Link to the page so it opens in a new tab, as Firefox's own error page suggests, or fetch its HTML as text and render a preview. news.ycombinator.com sends X-Frame-Options: DENY and frame-ancestors 'self'; through https://proxy.cors.dev/ (free, no key, GET, text up to 1 MiB) its HTML came back with status 200 in all 3 engines.
// news.ycombinator.com sends X-Frame-Options: DENY, so we show its content instead of framing it
const target = 'https://news.ycombinator.com/';
const response = await fetch('https://proxy.cors.dev/' + target, { credentials: 'omit' });
if (!response.ok) {
throw new Error(response.headers.get('X-Cors-Error') ?? `HTTP ${response.status}`);
}
const page = new DOMParser().parseFromString(await response.text(), 'text/html');
const stories = [...page.querySelectorAll('.titleline > a')].slice(0, 5).map((link) => ({
title: link.textContent,
url: new URL(link.getAttribute('href'), target).href,
}));
console.table(stories);Good questions.
Why does my iframe say refused to connect?
That is Chrome's error page for net::ERR_BLOCKED_BY_RESPONSE: the site answered, but its X-Frame-Options or frame-ancestors header does not allow your origin to frame it. Only the site's owner can change that.
Does X-Frame-Options ALLOW-FROM still work?
No. Chromium 153, Firefox 155 and WebKit 26.6 ignored it and loaded the frame, so the header protected nothing. Use frame-ancestors with the origins you allow.
Can I send X-Frame-Options and frame-ancestors together?
Yes. With both present, all 3 engines followed frame-ancestors, and Firefox logged that it was ignoring X-Frame-Options.
Why is a localhost image blocked as NotSameOrigin?
Two ports are two origins, so Cross-Origin-Resource-Policy: same-origin, the helmet() default, blocks an image on port 8002 for a page on port 8001. Send same-site or cross-origin instead.
Can JavaScript detect a blocked iframe?
Not from the embedding page alone: load fires and contentWindow access throws either way. A postMessage from a framed page you control is the reliable check.
Can a CORS proxy fix ERR_BLOCKED_BY_RESPONSE?
Not for frames. A CORS proxy makes a response readable by your script; it does not make a page embeddable. For third-party pages, fetch the HTML and show a preview.