X-Frame-Options and CSP frame-ancestors both stop clickjacking by controlling which sites are allowed to embed your page in a frame or iframe — but frame-ancestors is the modern replacement for the older, coarser X-Frame-Options. X-Frame-Options (2008) offers only two working values, DENY and SAMEORIGIN, and its third value ALLOW-FROM is deprecated and unsupported. CSP frame-ancestors (Content Security Policy Level 2) accepts a list of allowed origins and wildcards, and where both headers are present, any browser that supports CSP obeys frame-ancestors and ignores X-Frame-Options. The recommendation: use frame-ancestors as your real policy, and keep X-Frame-Options: SAMEORIGIN (or DENY) only as a fallback for very old browsers that never implemented CSP.
That is the summary. The rest of this article is the part an AI overview can't give you: the exact syntax and precedence rules, a side-by-side comparison, correct header examples you can paste, and the specific mistakes — deprecated ALLOW-FROM, meta-tag frame-ancestors, conflicting policies — that quietly leave a "protected" page fully frameable.
Clickjacking Protection: Two Headers, One Goal
Clickjacking attacks trick users into clicking invisible iframes overlaid on seemingly legitimate content, causing unintended actions like transferring money, changing settings, or authorizing access. Two HTTP headers protect against this threat: the older X-Frame-Options and the newer CSP frame-ancestors directive.
The diagram below shows the core mechanic — an attacker page tries to load your page in a hidden iframe, and the framing header refuses.
Understanding which to use—or why to use both—is essential for comprehensive clickjacking protection.
At a Glance: X-Frame-Options vs CSP frame-ancestors
| X-Frame-Options | CSP frame-ancestors | |
|---|---|---|
| Values / syntax | DENY, SAMEORIGIN, ALLOW-FROM uri (deprecated) | 'none', 'self', host list, scheme/host wildcards |
| Multiple allowed origins | No — single value only | Yes — list any number of origins |
| Wildcards | No | Yes (e.g. https:, *.example.com) |
| Delivery | HTTP response header only | HTTP response header only (ignored in <meta>) |
| Browser support | All browsers, including IE8+ | All modern browsers since 2016 (no IE) |
| Precedence when both present | Ignored by CSP-aware browsers | Wins — obeyed, X-Frame-Options ignored |
| Status | Legacy / superseded | Current standard |
| Example header | X-Frame-Options: SAMEORIGIN | Content-Security-Policy: frame-ancestors 'self' https://trusted.example |
Which should you use? Lead with frame-ancestors; keep X-Frame-Options only as a fallback for very old browsers.
X-Frame-Options: The Legacy Standard
X-Frame-Options was introduced by Microsoft in 2008 and became an industry standard for preventing pages from being embedded in frames.
Syntax and Values
DENY: Never allow framing
X-Frame-Options: DENY
SAMEORIGIN: Allow framing only by same origin
X-Frame-Options: SAMEORIGIN
ALLOW-FROM uri: Allow specific origin (deprecated, poor browser support)
X-Frame-Options: ALLOW-FROM https://trusted.com
Advantages
Wide browser support: Works in all browsers including Internet Explorer 8+ Simple implementation: Single header with straightforward values Proven track record: Over 15 years of deployment experience
Limitations
Single value only: Cannot specify multiple allowed origins ALLOW-FROM deprecated: Modern browsers removed support No granular control: Binary allow/deny per origin Being superseded: CSP frame-ancestors is the modern replacement
CSP frame-ancestors: The Modern Approach
frame-ancestors is part of Content Security Policy Level 2, offering more flexible frame control:
Syntax
Content-Security-Policy: frame-ancestors 'none'
Content-Security-Policy: frame-ancestors 'self'
Content-Security-Policy: frame-ancestors 'self' https://trusted.com https://another-trusted.com
Values
'none': Equivalent to X-Frame-Options: DENY 'self': Equivalent to X-Frame-Options: SAMEORIGIN Multiple origins: List any number of allowed domains Wildcard schemes: Use https: to allow all HTTPS origins
Advantages
Multiple origins: Allow framing by several specific domains Granular control: Precise whitelisting of trusted framers CSP integration: Part of broader security policy Modern standard: Recommended by security experts
Browser Support
Supported by all modern browsers since 2016, but legacy browser support lags behind X-Frame-Options.
Which Should You Use?
Lead with CSP frame-ancestors, and keep X-Frame-Options only as a fallback. frame-ancestors is the current standard, more flexible, and where both headers are present it takes precedence — CSP-aware browsers obey it and ignore X-Frame-Options entirely. X-Frame-Options earns its place solely by covering browsers so old they never implemented CSP.
Dual Implementation (belt and braces)
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
Modern browsers use frame-ancestors for its flexibility and precedence; the rare legacy browser falls back to X-Frame-Options. This approach gives you:
Maximum compatibility: protection across old and new browsers Defense in depth: a redundant policy if one header is stripped by a proxy No real cost: both headers are tiny and set once at the server
When CSP frame-ancestors Alone Suffices
Every browser released since 2016 supports frame-ancestors, so if you have no meaningful legacy-browser (IE11, very old mobile) traffic, frame-ancestors on its own is complete protection — with greater flexibility than X-Frame-Options could ever offer. Only send both when you actually need the legacy fallback.
Implementation Examples
Complete Denial
Block all framing:
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
Use for: Login pages, payment forms, administrative interfaces
Same-Origin Only
Allow framing only by your own site:
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
Use for: Applications where different pages frame each other
Multiple Trusted Origins
Allow specific external sites (CSP only):
Content-Security-Policy: frame-ancestors 'self' https://partner1.com https://partner2.com
X-Frame-Options cannot express this—use SAMEORIGIN as fallback:
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self' https://partner1.com https://partner2.com
Older browsers get less permissive policy (SAMEORIGIN) while modern browsers allow listed partners.
Common Mistakes
Conflicting Headers
Problem: Different policies in X-Frame-Options and frame-ancestors
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'none'
Result: Modern browsers use frame-ancestors ('none'), old browsers use X-Frame-Options (SAMEORIGIN), creating inconsistent protection
Solution: Make policies equivalent or intentionally more restrictive in X-Frame-Options
Using Deprecated ALLOW-FROM
Problem:
X-Frame-Options: ALLOW-FROM https://trusted.com
Result: Ignored by most modern browsers
Solution: Use CSP frame-ancestors for multiple origins, X-Frame-Options: SAMEORIGIN for legacy fallback
Missing from All Responses
Problem: Headers only on some responses, not all
Result: Unprotected pages can be framed
Solution: Set headers at web server level for all responses
Testing Frame Protection
Verify implementation:
Browser Developer Tools: Check Response Headers in Network tab
Manual Test: Attempt to embed page in iframe:
<iframe src="https://yoursite.com"></iframe>
Should result in console error: "Refused to display in a frame because it set 'X-Frame-Options' to 'deny'"
Security Scanners: Use Security Headers Analyzer
Exceptions: When to Allow Framing
Some legitimate use cases require framing:
Embedded widgets: Maps, videos, social media embeds Partner integrations: Trusted third parties embedding your content Internal applications: Dashboards framing various internal tools
For these scenarios:
- Use CSP frame-ancestors with specific allowed origins
- Never use 'unsafe-inline' or overly broad whitelists
- Regularly audit which origins are allowed
- Consider alternative integration methods (APIs, redirects)
Conclusion
Both X-Frame-Options and CSP frame-ancestors prevent clickjacking by controlling where your pages can be framed. X-Frame-Options offers broader legacy browser support but limited flexibility. CSP frame-ancestors provides granular control with multiple allowed origins but doesn't support very old browsers.
The best practice is to lead with CSP frame-ancestors and keep X-Frame-Options as an equivalent (or more restrictive) fallback. Modern browsers use frame-ancestors for its flexibility and precedence, while the rare legacy browser falls back to X-Frame-Options. This ensures comprehensive protection across all browsers without relying on a header that has been superseded.
For maximum security on sensitive pages (login, payments, admin), use DENY/'none' to block all framing. For less sensitive content needing selective framing, use CSP frame-ancestors with explicitly whitelisted trusted origins and X-Frame-Options: SAMEORIGIN as fallback.
Validate your frame protection implementation with our Security Headers Analyzer to ensure proper configuration and comprehensive clickjacking defense.