Refused to display in a frame because an ancestor violates frame-ancestors / X-Frame-Options

An embed is blank, the console says the page “refused to display in a frame”, and your payment widget, docs iframe or admin preview is empty. The page is blocking being framed — usually on purpose.

What the error means

Browsers show one of these (wording varies slightly):

The check runs on the document inside the iframe. Your outer page is fine; the inner response's headers said “don't let this parent embed me.” That is clickjacking defence: without it, a hostile site could overlay invisible UI on top of your logged-in page and steal clicks.

DENY vs SAMEORIGIN vs frame-ancestors

HeaderEffectNotes
X-Frame-Options: DENYNobody may frame the page, not even the same siteOldest, widely supported
X-Frame-Options: SAMEORIGINOnly the exact same origin (scheme + host + port)Subdomains do not count
X-Frame-Options: ALLOW-FROM https://partner.exampleLegacy IE onlyChromium, Firefox and Safari ignore it
Content-Security-Policy: frame-ancestors 'none'Same idea as DENYModern replacement; not allowed in a <meta> tag
frame-ancestors 'self'Same idea as SAMEORIGINPreferred over XFO
frame-ancestors 'self' https://trusted.exampleYou plus listed parentsHow to allow a real embed partner

When both XFO and frame-ancestors are present, modern browsers obey frame-ancestors and ignore XFO for framing. default-src never covers frame-ancestors — you must set it yourself. Paste your headers into the X-Frame-Options & frame-ancestors explainer to see the effective rule and try attacker origins. From a script or CI job, the free Anvil framing / clickjacking API returns the same grade and check as JSON.

Allow a trusted parent

# Prefer CSP (overrides XFO when both are sent)
Content-Security-Policy: frame-ancestors 'self' https://trusted.example https://*.partner.example;

# nginx
add_header Content-Security-Policy "frame-ancestors 'self' https://trusted.example" always;

# Express
res.setHeader("Content-Security-Policy", "frame-ancestors 'self' https://trusted.example");

List every parent that must embed you, including preview domains and local dev (http://localhost:3000) if needed. Wildcards cover one DNS label (*.partner.example matches a.partner.example, not partner.example itself). After changing headers, hard-refresh; CDNs and service workers can cache the old policy.

How to harden (when you are the framed site)

Related

Refused to execute inline script (CSP) · CSP header explainer · CSRF token missing · CORS errors · CSP Report-Only vs Enforce · Wirebook bots lesson · NotAllowedError getUserMedia (iframe allow)

Questions

What does 'an ancestor violates frame-ancestors' mean?

The page inside the iframe sent a CSP frame-ancestors list that does not include the parent page's origin, so the browser refuses to paint it.

How do I allow my site to be embedded by a partner?

On the framed site, send Content-Security-Policy: frame-ancestors 'self' https://partner.example (plus any other parents). Prefer that over X-Frame-Options ALLOW-FROM.

Why does SAMEORIGIN block my subdomain?

SAMEORIGIN and 'self' mean the exact origin. www.example.com and app.example.com are different. List each host in frame-ancestors, or use a matching wildcard carefully.

Does removing X-Frame-Options fix a blank iframe?

It might, but only do that if the page is meant to be public to embed. For logins and payments, keep DENY / 'none' and embed a dedicated public widget instead.

Can a sandboxed iframe bypass the block?

No. Sandbox does not override X-Frame-Options or frame-ancestors.

Published .

Try it

Related guides

Newest guides