headers error

Refused to display in iframe: X-Frame-Options or CSP frame-ancestors

The error

Refused to display 'https://example.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.

What it means

The page you’re trying to embed is configured to refuse iframe embedding from other sites. This is intentional protection against clickjacking.

X-Frame-Options: DENY blocks all framing. SAMEORIGIN allows only same-origin frames. Modern sites use CSP frame-ancestors instead — same effect. Without your site listed in the framed page’s policy, the browser refuses to render.

The fix

On the framed page (the one that sets the policy)
// app/middleware.ts (Next.js) — to allow yoursite.com to embed this page:
export function middleware(req: NextRequest) {
  const res = NextResponse.next();
  res.headers.set(
    'Content-Security-Policy',
    "frame-ancestors 'self' https://yoursite.com",
  );
  // remove the legacy header — it conflicts with frame-ancestors
  res.headers.delete('X-Frame-Options');
  return res;
}

Also check

Common adjacent root causes when the obvious fix doesn’t work.

  • 01You may not control the framed page (e.g. you’re embedding YouTube, Stripe Checkout). In that case, redirect the user instead of framing.
  • 02If you control both pages, prefer CSP frame-ancestors over X-Frame-Options. The legacy header has no syntax for multiple origins.
  • 03Setting both headers with conflicting values? Browsers prefer CSP. Remove X-Frame-Options.

Scan for related issues

This error is in our headers scanner. Run a free scan to find what else is misconfigured in the same area.

FAQ

Frequently asked questions

I added frame-ancestors but it still blocks. Why?
Browsers honor the strictest of X-Frame-Options and CSP frame-ancestors. Make sure both allow framing — or, better, remove X-Frame-Options entirely and rely on CSP.
Is allowing framing dangerous?
It can be — clickjacking attacks rely on framing your site over a malicious one. Only allow specific trusted origins, never "*".