sfw/fix
X-Frame-Options: SAMEORIGIN medium

"Refused to display in a frame because it set 'X-Frame-Options' to 'sameorigin'"

An anti-clickjacking header on the target page blocks it from being embedded in an iframe on a different domain, so the frame renders blank.

What you see

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

What’s actually happening

You drop a site into an <iframe> and get a blank box — no content, no error in the page itself. The reason is in the DevTools Console: a "Refused to display … in a frame" line. This is the framed site protecting itself, not a bug in your embedding page. You can't override it from your side by editing the iframe; the header lives on the response from the other origin.

Common causes

  • The target page sends X-Frame-Options: SAMEORIGIN, so it only frames on its own domain — embedding from yours is refused
  • The target sends X-Frame-Options: DENY, which blocks framing on every domain including its own
  • A Content-Security-Policy frame-ancestors directive on the target that doesn't include your domain (modern replacement for XFO; takes precedence when both are present)
  • Trying to iframe a service that deliberately blocks embedding (Google, YouTube watch pages, banks, many SaaS apps) instead of using its official embed URL
  • A reverse proxy, CDN, or security plugin injecting XFO/frame-ancestors that the app owner didn't realize was there

How to fix it

  1. Decide whether you control the framed siteThis header is set by the page being embedded. If it's not your site, you can't remove it from the embedding side — full stop. The fix is either use an official embed path or stop iframing it. If it is your site (or your company's), you can adjust the header on that origin.
  2. Use the official embed URLMost services that block /watch or app pages still offer an embeddable endpoint: YouTube → youtube.com/embed/VIDEO_ID, Google Maps → its Embed iframe, etc. These responses are sent without the blocking header (or with frame-ancestors that permit framing). Swap the iframe src to that URL.
  3. Relax frame-ancestors on your own originIf you own the framed page, prefer CSP over the legacy header. Drop X-Frame-Options and set Content-Security-Policy: frame-ancestors 'self' https://embedder.example.com — listing exactly the parent origins allowed to embed it. frame-ancestors supports multiple hosts and is what current browsers honor; keeping a conflicting XFO header can still cause a block.
  4. Check for a proxy or plugin injecting the headerIf your own app suddenly refuses to frame and you didn't set XFO, inspect the actual response headers (curl -I https://yoursite). A CDN, WAF, nginx add_header, or a WordPress security plugin may be adding SAMEORIGIN. Remove or adjust it at that layer, then re-check the headers.

Stop it recurring

On pages meant to be embedded, drop X-Frame-Options and use a CSP frame-ancestors allowlist naming exactly the origins permitted to frame them.

Related errors