Fix PDFs and Iframes Not Loading in WordPress – X-Frame-Options Guide
January 15, 2024
This tutorial has moved to the new WP Ghost Knowledge Base where each feature is presented in detail.
Quick summary: PDFs or iframes that stop loading after you turn on WP Ghost’s security headers are blocked by one of two headers. X-Frame-Options decides which sites can frame your pages, and Content-Security-Policy decides what your pages can embed. Fix the header that’s blocking, without turning off the protection.
Why security headers can block iframes and PDFs
WP Ghost can add security headers to every HTTP response from your server. One of them is X-Frame-Options, which protects your site from clickjacking attacks; when it’s in the list, WP Ghost’s default value is SAMEORIGIN. Clickjacking is when an attacker loads your page inside an invisible iframe on their site and tricks visitors into clicking on it.
Your X-Frame-Options header doesn’t decide what your own pages can embed. An iframe on your page that loads another site follows that site’s own X-Frame-Options, plus your Content-Security-Policy: if your policy has a frame-src directive, the other domain has to be listed in it.
This affects two common scenarios: embedding PDFs from external services (Google Drive, Dropbox, third-party document hosts) and loading iframes from other domains (payment forms, booking widgets, video embeds, maps).
How X-Frame-Options works
X-Frame-Options tells browsers whether your page can appear inside a frame element on another site. It has two standard values:
DENY blocks all framing entirely. No site, not even your own, can load your pages in an iframe. This is the most restrictive setting.
SAMEORIGIN allows framing only from your own domain. Your site can iframe its own pages, but external domains cannot frame your content. This is the default WP Ghost setting and works well for most WordPress sites.
The confusion usually comes from a misunderstanding of direction. X-Frame-Options controls whether your pages can be framed by others. When you embed content from another domain, the browser checks the X-Frame-Options header that the other server sends. If that header refuses framing, the iframe fails to load on your page.

What breaks and what does not
Here is a quick reference to help you identify whether your setup is affected.
| Scenario | X-Frame-Options: SAMEORIGIN | Result |
|---|---|---|
| Local PDF embedded in iframe (same domain) | Allowed | Loads normally |
| External PDF from Google Drive or Dropbox | Not controlled by your header | Blank if the host refuses framing |
| YouTube or Vimeo video embed | Usually works | These services send permissive headers |
| Third-party booking or payment iframe | Depends on the service | Check their X-Frame-Options header |
| Page builder live preview (same domain) | Allowed | Loads normally |
| Google Maps embed | Usually works | Google sends permissive headers |
The key takeaway: if both your site and the embedded content are on the same domain, SAMEORIGIN allows it. If the content comes from a different domain, the browser may block it depending on the headers that external server sends back.
The PDF loading problem
PDFs embedded in iframes are a common case. Many WordPress sites use plugins or shortcodes to display PDFs directly on a page. When those PDFs are hosted on your own server, they load fine under SAMEORIGIN. If a plugin embeds the PDF with an <object> or <embed> tag instead, the Content-Security-Policy object-src directive applies, and WP Ghost’s default value object-src 'none' blocks it even on your own domain. Embed the PDF in an iframe, or add the PDF’s source to object-src.
The problem shows up when the PDF is hosted externally. For example, a Google Drive shared link or a Dropbox file embed. The browser tries to load the external URL in the iframe, checks the X-Frame-Options header from that external server, and blocks it if the policy does not allow cross-origin framing.

How to fix it
Option 1: Use Content-Security-Policy instead
Content-Security-Policy covers both directions. Its frame-ancestors directive, the modern replacement for X-Frame-Options, decides which sites can frame your pages. Its frame-src directive decides which domains your pages can load in iframes.
1. Go to WP Ghost > Firewall > Header Security.
2. To let another site frame your pages, remove X-Frame-Options with the X next to its name and use frame-ancestors instead (step 3).
3. In the Content-Security-Policy value, add the directive you need. To let a partner site frame your pages: frame-ancestors 'self' https://partner.example.com; To embed Google Drive files when your policy has a frame-src or default-src directive: frame-src 'self' https://docs.google.com https://drive.google.com;
4. Click Save.
Don’t use ALLOW-FROM in X-Frame-Options to allow other domains: MDN marks it obsolete, and modern browsers ignore the whole header when they see it.
Option 2: Host the content locally
The simplest fix is to upload the PDF or content to your own WordPress Media Library. When both the page and the embedded file live on the same domain, SAMEORIGIN allows it without any extra configuration.
1. Go to Media > Add New in your WordPress dashboard.
2. Upload the PDF file.
3. Use the local URL (your own domain) in the iframe embed instead of the external link.
This approach keeps your security headers fully intact while solving the loading issue.
Option 3: Keep X-Frame-Options for the rest of the site
WP Ghost sends its security headers for the whole site, so the clickjacking protection should stay on for every page that doesn’t need an exception.
1. Go to WP Ghost > Firewall > Header Security.
2. Keep X-Frame-Options set to SAMEORIGIN for general protection.
3. Fix the pages that need external embeds with Option 1 or Option 2. Excluding a page with Disable WP Ghost on Specific Pages turns off WP Ghost’s path changes on it, not the headers.
This way your entire site keeps its clickjacking protection, and only the embeds you allowed load from other domains.
How to check which header is causing the problem
Before changing any settings, confirm that X-Frame-Options is actually the cause. Open your browser’s Developer Tools (press F12), go to the Console tab, and load the page with the broken iframe. You will see an error message like:
Refused to display 'https://example.com/file.pdf' in a frame because it set 'X-Frame-Options' to 'sameorigin'.
If you see this error, X-Frame-Options is the cause. If the error mentions Content-Security-Policy instead, check the frame-src or frame-ancestors directive in your CSP configuration.
Frequently asked questions
Should I just disable X-Frame-Options entirely?
No. Disabling it removes your clickjacking protection completely. Use Content-Security-Policy frame-ancestors instead. It gives you the same protection with more flexibility to allow specific domains.
Why do YouTube and Google Maps embeds still work?
Their embed URLs don’t send a restrictive X-Frame-Options header, so other sites can frame them. An embed fails when the service’s own header refuses framing, or when your Content-Security-Policy has a frame-src directive that doesn’t list the domain.
Does this problem only happen in Ghost Mode?
No. It happens whenever the security headers are on, whatever the security level. Most security presets switch them on, which is when most users notice it.
Will changing X-Frame-Options affect my SEO?
No. Search engines do not use X-Frame-Options for ranking. Your pages, sitemaps, and canonical URLs are completely unaffected by this header. It only controls browser iframe behavior.
My page builder preview is broken. Is this the same issue?
Yes, it can be. Some page builders like Elementor, Divi, and Beaver Builder use iframes for live previews. If X-Frame-Options is set to DENY, the preview will break. Set it to SAMEORIGIN to fix it, since the preview loads from your own domain.
Does WP Ghost modify WordPress core files?
No. WP Ghost adds security headers through server configuration files and PHP filters. No core files are touched. Disabling the header option removes it instantly.
Related tutorials
For a deeper understanding of security headers and how they protect your site, check these tutorials:
Header Security – Complete guide to the security headers WP Ghost can send, including setup and testing.
Content Security Policy (CSP) – CSP configuration with five ready-to-use examples for WordPress.
Disable WP Ghost on Specific Pages – How to exclude individual pages from WP Ghost’s security features.
Activate Security Tweaks – Overview of all security hardening options available in WP Ghost.
Preset Security Options – One-click security configurations including header presets.