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 example frame-src 'none', blocked the frame.
  • net::ERR_BLOCKED_BY_ORB: an img or script tag 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

Which response header blocks what, and Chromium's error for it (Chromium 153, Firefox 155 and WebKit 26.6 behaved the same unless noted), checked October 2026
Header and valueWhat it blocksChromium 153 errorFix
X-Frame-Options: DENYEvery frame, your own origin includednet::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: SAMEORIGINFrames on other originsnet::ERR_BLOCKED_BY_RESPONSE; console: same line, set to 'sameorigin'.frame-ancestors 'self' plus the origins you allow
X-Frame-Options: ALLOW-FROM originNothing: all 3 engines ignore the headerNone, 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 originFrames on every origin not listednet::ERR_BLOCKED_BY_RESPONSE; console: Framing '...' violates the following Content Security Policy directiveAdd the embedding origin to the list
frame-ancestors in a meta tagNothing: ignored in all 3 enginesNone, the frame loads; console: ... is ignored when delivered via a <meta> element.Send it as an HTTP response header
Cross-Origin-Resource-Policy: same-originimg, script and no-cors fetch from other origins, other ports includednet::ERR_BLOCKED_BY_RESPONSE.NotSameOriginCross-Origin-Resource-Policy: cross-origin
Cross-Origin-Resource-Policy: same-siteThe same loads from other sitesnet::ERR_BLOCKED_BY_RESPONSE.NotSameSitecross-origin, or serve both from one site
Your page sends Cross-Origin-Embedder-Policy: require-corp, the file has no CORPCross-origin img and script without CORP or CORSnet::ERR_BLOCKED_BY_RESPONSE.NotSameOriginAfterDefaultedToSameOriginByCoepCORP cross-origin on the file, crossorigin plus CORS, or COEP credentialless
Your page sends COEP require-corp, the framed page lacks COEP and CORPCross-origin iframesnet::ERR_BLOCKED_BY_RESPONSE; no console line, Issues panel onlyThe 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 logs Refused 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 logs Refused 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 logs Cancelled 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 or Refused 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

  1. 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 drop X-Frame-Options; frame-ancestors overrides it.

  2. Images, scripts and files

    on the server that serves them, send Cross-Origin-Resource-Policy: cross-origin, or same-site when both origins share a site. CORP does not apply to CORS requests: a fetch() in cors mode to a file with Access-Control-Allow-Origin: * and CORP same-origin returned 200 in all 3 engines.

  3. Pages with COEP

    have the files send CORP cross-origin, or add crossorigin="anonymous" to the tag and send Access-Control-Allow-Origin from the file server, or switch to Cross-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 CORP cross-origin; credentialless did not relax that. The Cross-Origin-Opener-Policy guide covers the isolation side.

Express with helmet: allow named origins to frame you and share your files
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'),
  });
});

The same fix in a _headers file
# _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-origin

When 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.

Can't embed a site you don't own? Show its content instead
// 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.