Back to knowledge center
X-Frame-Options: What It Does and How to Configure It Right
security David Lindgren 7 min8/18/2026

X-Frame-Options: What It Does and How to Configure It Right

X-Frame-Options tells browsers whether your site may be embedded in a frame, and it is the classic defense against clickjacking. Here is how DENY and SAMEORIGIN work, which values silently fail, and when to switch to CSP frame-ancestors.

Run the same check right now โ€“ free

Enter your domain and get a 9-point audit โ€“ DNS, SPF/DKIM/DMARC, SSL, security headers, dark-web exposure โ€“ in 60 seconds.

No signup ยท <60s ยท No personal data required

X-Frame-Options is an HTTP response header that tells the browser whether your page may be rendered inside a frame or iframe on another site. It has exactly two valid values: DENY (no framing at all) and SAMEORIGIN (framing allowed only from your own origin). Its purpose is to stop clickjacking, an attack where your site is loaded invisibly inside an attacker's page and your visitors are tricked into clicking things they cannot see. The modern replacement is the Content-Security-Policy directive frame-ancestors, and the 2026 best practice is to send both headers. This guide covers the correct setup for every major server, plus the mistakes that silently disable the protection.

What the X-Frame-Options header does

When a browser loads a page that another document has embedded through <iframe>, <frame>, <embed> or <object>, it checks the response headers of the embedded page before rendering it. If the response carries X-Frame-Options: DENY, the browser refuses to draw the page inside the embedding document. With SAMEORIGIN, it renders the page only if the embedding chain comes from the same origin (same scheme, host and port). Modern browsers evaluate the entire chain of ancestor frames, not just the top window.

The header was formalized in RFC 7034 in October 2013, after browsers had already shipped it. It remains one of the most widely deployed security headers: the HTTP Archive Web Almanac 2025 security chapter measures X-Frame-Options on roughly 35% of mobile sites, making it a top three security header behind X-Content-Type-Options (close to 50%).

Clickjacking in 60 seconds

Clickjacking was named by security researchers Robert Hansen and Jeremiah Grossman in 2008. The attack is simple: an attacker's page loads your site in an iframe, makes the iframe fully transparent with CSS, and positions it over harmless looking buttons. The visitor believes they are clicking "Play video", but the click actually lands on your site's "Delete account", "Confirm payment" or "Authorize app" button, using the victim's logged-in session. OWASP documents variants ranging from Facebook "likejacking" to hijacked one-click purchases.

Framing control is the defense. If the browser refuses to render your page inside an attacker's frame, the overlay trick collapses.

Developer reviewing web server configuration code on a laptop screen

The two valid values, and the ones to avoid

ValueEffectStatus in 2026
DENYNo site may frame the page, including your ownValid, supported by all browsers
SAMEORIGINOnly pages from the same origin may frame itValid, supported by all browsers
ALLOW-FROM uriWas meant to allow one named originObsolete: Firefox removed it in version 70 (October 2019), Chrome and Safari never supported it
ALLOWALLNever part of any specInvalid: browsers ignore the header entirely, leaving no protection

The dangerous part is how browsers handle invalid values: they ignore the whole header. A site sending ALLOW-FROM or ALLOWALL believes it is protected while browsers treat it as if no header were set. As the Web Almanac 2025 puts it, these values "may have been set by developers expecting protections to be active due to them setting the header."

What real-world data shows

Across millions of sites measured by HTTP Archive in 2025, the header's values break down like this:

Bar chart showing the distribution of X-Frame-Options values on mobile sites in 2025: SAMEORIGIN 72.1 percent, DENY 24.6 percent, ALLOWALL 0.7 percent, other or invalid values 2.5 percent

Source: HTTP Archive Web Almanac 2025, security chapter, figure 9.30 (mobile dataset).

About 72.1% of sites that send the header choose SAMEORIGIN and 24.6% choose DENY. Roughly 3% send values that do nothing, which on the scale of the web is hundreds of thousands of sites with imaginary protection. Checking what your server actually sends takes less than a minute.

X-Frame-Options vs CSP frame-ancestors

The W3C Content Security Policy Level 2 specification (a W3C Recommendation since December 2016) introduced the frame-ancestors directive and formally obsoleted X-Frame-Options. Where XFO is a blunt on/off switch, frame-ancestors is a full allowlist:

CapabilityX-Frame-OptionsCSP frame-ancestors
Block all framingDENYframe-ancestors 'none'
Allow own origin onlySAMEORIGINframe-ancestors 'self'
Allow named partner originsNot possible (ALLOW-FROM is dead)frame-ancestors 'self' https://partner.example.com
Wildcard subdomainsNot possibleframe-ancestors https://*.example.com
Spec statusInformational RFC 7034 (2013), obsoletedW3C CSP Level 2 (2016), current standard
When both headers are presentIgnored by CSP2-capable browsersTakes precedence

Two details worth knowing. First, MDN notes that frame-ancestors does not inherit from default-src: a policy of default-src 'none' still allows anyone to frame the page, so you must declare the directive explicitly. Second, all current versions of Chrome, Edge, Firefox and Safari support frame-ancestors, so the only reason to keep sending X-Frame-Options is defense in depth for very old clients. That costs one line, so keep it.

How to configure it on your server

Send the header on every HTML response, exactly once. The examples below set SAMEORIGIN plus the equivalent CSP directive.

nginx (inside server or location):

add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self';" always;

Apache 2.4 (httpd.conf or .htaccess, mod_headers enabled):

Header always set X-Frame-Options "SAMEORIGIN"
Header always set Content-Security-Policy "frame-ancestors 'self';"

IIS (web.config):

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="X-Frame-Options" value="SAMEORIGIN" />
      <add name="Content-Security-Policy" value="frame-ancestors 'self';" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

Node.js with Express and Helmet:

const helmet = require("helmet");
app.use(helmet.frameguard({ action: "sameorigin" }));
app.use(helmet.contentSecurityPolicy({
  directives: { frameAncestors: ["'self'"] }
}));

Behind a CDN such as Cloudflare you can also inject both headers with a response header transform rule, which is useful when you cannot touch the origin server. If a partner site legitimately needs to embed you, keep XFO at SAMEORIGIN and express the allowlist in CSP: frame-ancestors 'self' https://partner.example.com.

Mistakes that silently disable the protection

  • Using ALLOW-FROM in 2026. Every current browser ignores it, and with it the whole header.
  • Setting the header in a meta tag. X-Frame-Options only works as an HTTP header, and frame-ancestors is explicitly forbidden inside <meta http-equiv="Content-Security-Policy">. Both must come from the server.
  • Sending the header twice. Duplicate or comma-joined values such as SAMEORIGIN, SAMEORIGIN (0.28% of sites in the Almanac 2025 data) can be rejected as invalid. Set it in one place only, either the app or the web server, not both.
  • Using DENY on pages you embed yourself. If your own checkout, widget or preview runs in an iframe, DENY breaks it. Use SAMEORIGIN or an explicit frame-ancestors allowlist.
  • Assuming default-src covers framing. It does not. Declare frame-ancestors explicitly.

How to test your configuration

Open your browser's developer tools, load your page, and inspect the response headers on the main document: you should see exactly one X-Frame-Options and a Content-Security-Policy containing frame-ancestors. For the full picture, the free FortifyNet scan checks your framing protection together with the rest of your security header set, SSL/TLS, DNS and email authentication in about 60 seconds, and tells you exactly which header to add where. No signup needed.

FAQ

Is X-Frame-Options deprecated? Formally yes: W3C CSP Level 2 obsoleted it in favor of frame-ancestors back in 2016. In practice every browser still honors it, and OWASP recommends sending both headers for defense in depth. The one thing you must not do is rely on ALLOW-FROM.

Should I use DENY or SAMEORIGIN? Use DENY if nothing on your site is ever shown in a frame, which is the strongest setting. Use SAMEORIGIN if your own pages embed each other, for example dashboards, previews or internal widgets. In the 2025 Web Almanac data, 72.1% of sites choose SAMEORIGIN.

How do I allow one specific partner site to embed my pages? X-Frame-Options cannot do this anymore. Use Content-Security-Policy: frame-ancestors 'self' https://partner.example.com and list each allowed origin explicitly.

What happens if I send both X-Frame-Options and frame-ancestors? Browsers that support CSP Level 2, which is all modern ones, enforce frame-ancestors and ignore X-Frame-Options. Older clients fall back to X-Frame-Options. That fallback chain is exactly why sending both is the recommended setup.

Can I set X-Frame-Options with a meta tag? No. Browsers only honor it as a real HTTP response header. If you cannot change server configuration, set it through your hosting panel, CDN rules or application middleware.

Frequently Asked Questions

#security headers#clickjacking#X-Frame-Options#CSP#frame-ancestors

Check your domain now

Run a free security audit and see if your domain has the issues described in this article.