How to Open a PDF in an HTML Iframe
Display a PDF in an HTML iframe with accessible markup, fallback links, Blob URLs, CSP guidance, and fixes for blank or blocked previews.
The simplest way to open a browser-accessible PDF in an HTML page is to point an <iframe> at the PDF URL. The browser supplies its built-in PDF viewer. Always place a normal open or download link beside the frame because an iframe has no reliable child-content fallback when the PDF viewer cannot render. MDN documents this iframe behavior and the fallback-link pattern.
1. Basic PDF iframe
<iframe
src="/files/guide.pdf"
title="PDF preview: user guide"
width="100%"
height="600"
loading="lazy">
</iframe>
<p>
<a href="/files/guide.pdf">Open or download the PDF</a>
</p>
Replace /files/guide.pdf with an ordinary HTTPS PDF URL. Use a descriptive title so screen-reader users know what the frame contains. Set a useful height; an iframe with no height may collapse or provide an impractical preview.
Use loading="lazy" when the preview is below the fold. Omit it when the PDF should load immediately. The external link should remain visible whether lazy loading is enabled or not.
2. A complete responsive example
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Guide preview</title>
<style>
.pdf-frame {
display: block;
width: 100%;
min-height: 70vh;
border: 1px solid #d0d7de;
border-radius: 8px;
}
</style>
</head>
<body>
<main>
<h1>User guide</h1>
<iframe
class="pdf-frame"
src="/files/guide.pdf"
title="PDF preview: User guide"
loading="lazy">
</iframe>
<p>
<a href="/files/guide.pdf">Open or download the User guide (PDF)</a>
</p>
</main>
</body>
</html>
The frame itself is responsive because its width is 100%. The minimum height prevents a tiny preview on short screens; choose a value appropriate for your layout.
3. Cross-origin PDFs and security headers
A PDF on another origin can be embedded if the browser permits the response to be framed. Check both sides of the policy:
- Parent page: its Content Security Policy
frame-srcdirective controls which iframe sources it may load. - PDF response: the PDF server can deny embedding with
X-Frame-Optionsor CSPframe-ancestors.
frame-src and frame-ancestors solve different problems. MDN’s frame-src reference covers the parent policy, while frame-ancestors and X-Frame-Options describe restrictions sent by the embedded response.
Content-Security-Policy: frame-src 'self' https://cdn.example.com;
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self' https://app.example.com;
If you control the PDF host, configure its response headers for the parent origins that should be allowed. A change to the parent page cannot override a denial sent by the PDF response.
4. Should you use iframe, object, or embed?
| Element | Use it when | Trade-offs |
|---|---|---|
iframe |
You want the straightforward native PDF preview. | Supports iframe features such as loading and referrerpolicy, but does not provide child fallback content. |
object |
You specifically need fallback markup inside the embedding element. | Verify behavior in the browsers you support. |
embed |
Rare legacy cases. | MDN identifies no advantage over iframe for an ordinary PDF preview. |
MDN’s embedding guide discusses these choices. Keep a separate link even when using object.
5. Using object when inline fallback is required
<object
data="/files/guide.pdf"
type="application/pdf"
width="100%"
height="600">
<p>
This browser cannot display the PDF inline.
<a href="/files/guide.pdf">Open or download the PDF</a>.
</p>
</object>
This gives you fallback content inside the element. Test the result in every target browser and retain a normal link outside or immediately below the preview for consistent navigation.
6. Displaying a PDF Blob with a temporary object URL
If a file input or a fetch() request gives you a Blob, create an object URL and assign it to the iframe. Release the URL when it is no longer needed.
<input id="pdf-file" type="file" accept="application/pdf">
<iframe id="pdf-frame" title="Selected PDF preview" width="100%" height="600"></iframe>
<p><a id="pdf-link" hidden>Open or download the PDF</a></p>
<script>
const input = document.querySelector('#pdf-file');
const frame = document.querySelector('#pdf-frame');
const link = document.querySelector('#pdf-link');
let objectUrl;
input.addEventListener('change', () => {
const file = input.files[0];
if (!file) return;
if (objectUrl) URL.revokeObjectURL(objectUrl);
objectUrl = URL.createObjectURL(file);
frame.src = objectUrl;
link.href = objectUrl;
link.hidden = false;
});
window.addEventListener('beforeunload', () => {
if (objectUrl) URL.revokeObjectURL(objectUrl);
});
</script>
For a fetched PDF, check the response before creating the URL:
const response = await fetch('/api/guide.pdf');
if (!response.ok) throw new Error(`PDF request failed: ${response.status}`);
const blob = await response.blob();
const objectUrl = URL.createObjectURL(blob);
document.querySelector('#pdf-frame').src = objectUrl;
// Call URL.revokeObjectURL(objectUrl) when the preview is removed.
MDN’s File API guidance covers object URLs and releasing them. Its example also notes a Firefox preference that can affect embedded PDF display; do not assume every browser has identical settings.
7. Useful iframe attributes
title: required for an understandable accessible name.loading="lazy": delays loading for below-the-fold previews.widthandheight: provide an initial viewing area; CSS is usually better for responsive sizing.referrerpolicy: controls the referrer sent while loading the PDF, subject to your privacy and analytics requirements.
Do not add sandbox reflexively. It can prevent the browser’s built-in PDF viewer from loading. The native viewer already sandboxes executable content, and a sandbox is not a portable way to impose extra restrictions on that viewer. See MDN’s sandbox notes.
8. Troubleshooting blank, blocked, or downloaded PDFs
The iframe is blank
- Open developer tools and inspect the console and network response.
- Check that the parent CSP
frame-srcallows the PDF origin. - Inspect the PDF response for
X-Frame-Optionsorframe-ancestors. - Confirm the URL returns a PDF rather than an authentication page, redirect loop, or HTML error.
- Use the external link to determine whether the document opens outside an iframe.
The browser downloads the PDF instead
Browser configuration and response behavior can affect whether a PDF opens inline. Keep the separate link and test the actual browser and PDF host you support. The iframe pattern does not guarantee identical behavior everywhere.
The PDF requires authentication
An iframe request may not have the credentials your application expects, especially across origins. Serve the file through an authorized route you control or provide a normal authenticated link. Do not expose private documents through a publicly guessable URL.
The frame works locally but not in production
Compare production CSP, response headers, redirects, TLS, and origin names. A production CDN may add framing restrictions that are absent from a local server.
Adding sandbox breaks the viewer
Remove sandbox unless you have verified the exact browser behavior and tokens required. It can stop the built-in viewer from loading.
The preview is too short or causes layout shift
Give the iframe a CSS height or minimum height before it loads. A viewport-relative value such as min-height: 70vh is a practical starting point.
9. Performance, reliability, and accessibility checklist
- Use
loading="lazy"for previews below the fold. - Keep the PDF reasonably sized; the native viewer still has to download and parse it.
- Serve the file over HTTPS and configure caching appropriate to how often it changes.
- Use a descriptive iframe
title. - Provide a visible open/download link outside the iframe.
- Do not depend on iframe fallback text to communicate failure.
- Test the target browsers, mobile layouts, authentication flow, CSP, and PDF response headers.
- For user-selected Blobs, revoke old object URLs to avoid retaining memory.
10. Or skip the browser setup
If you need a rendered capture of a webpage or document without maintaining browser automation, ScreenshotNeo provides a website screenshot API. Its endpoint can return PNG, JPEG, WebP, or PDF output; see the ScreenshotNeo documentation for request options.
One request:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots, and 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
11. FAQ
Can I put a PDF URL directly in iframe src?
Yes, when the URL is reachable by the browser and the PDF response permits framing. Keep a separate link for browsers or servers that do not render it inline.
Does iframe work for every PDF viewer?
No. The browser’s built-in viewer, user settings, response headers, and target browser all affect the result.
Can JavaScript read the PDF inside a cross-origin iframe?
Same-origin rules prevent ordinary page scripts from inspecting cross-origin iframe contents. You can still display the document when framing is allowed.
Should I use embed instead?
For ordinary PDF previews, MDN identifies no advantage over iframe. Choose object only when inline fallback markup is a specific requirement.
How do I let users download the file?
Provide a normal <a href="..." download> link when appropriate, or a standard link that opens the PDF. Server response headers and browser policy can influence whether it displays or downloads.


