PDF extraction

Embed PDF on HTML: A Comprehensive Guide 2026

Discover how to embed pdf on html effectively. Use native tags, JavaScript libraries like PDF.js, & dedicated viewers for responsive & secure content.

May 20, 2026 12 min read OkraPDF
embed pdf on htmlpdf viewer htmliframe pdfpdf to linkfree pdf hosting

You usually hit this problem in the middle of building something else. You've got a PDF URL, a page in your app that needs to display it, and about ten minutes before someone asks why the browser downloads the file instead of showing it inline.

The short answer is that embed pdf on html has three practical paths. Native HTML tags are the fastest. JavaScript viewers give you control. A dedicated service helps when the hard part isn't the tag, but the hosting, delivery, and access rules around the file.

If you only need a document visible on a page today, start with native HTML. If you need custom controls, search, or page-level rendering, move to a JavaScript viewer. If your team is also dealing with signed links, file hosting, and consistent delivery, you're solving a broader document workflow problem. If you've already looked at adjacent approaches like embedding PDFs through Google Docs, the same trade-offs still apply. You're choosing between speed, control, and operational overhead.

Table of Contents

Your Options for Displaying PDFs in HTML

When a developer asks how to embed a PDF in a page, the underlying question is usually one of these:

  • Need it fast: show a PDF inside a page with as little code as possible.
  • Need control: replace the browser's built-in viewer with your own UI.
  • Need reliability: handle hosting, sharing, permissions, and delivery without building that stack yourself.

Those are different jobs, and the implementation changes with the job.

Native tags like <iframe>, <embed>, and <object> are the quickest route. They work well when the PDF is public or already accessible from the browser, and when you can live with whatever viewer the browser decides to provide.

JavaScript viewers are what you use when the built-in browser controls aren't acceptable. That usually means custom zoom buttons, page navigation, search, text-layer access, or a UI that looks like your app instead of a browser plugin.

Managed services sit one level above both. They don't just render a document. They also help with stable file URLs, CDN delivery, access control, and the messy parts of the PDF lifecycle that often show up after the first demo works.

Practical rule: Pick the simplest method that still gives you the user experience you actually need. Most teams overbuild too early or underbuild and then have to unwind browser quirks later.

The Quick Way with Native HTML Tags

If you need a PDF on the page right now, native HTML is still the fastest solution. A practical browser-native pattern is to use <iframe>, <embed>, or <object> with type="application/pdf", and to prefer percentage-based sizing like width="100%" plus a fixed height or wrapper so it scales across desktop and mobile, as noted in this browser-native embedding guide.

A hand placing a PDF file into a web browser window surrounded by HTML tag labels

The upside is obvious. No package install, no viewer bundle, no client-side rendering code. The downside is just as real. Native PDF embeds don't behave uniformly across browsers, and they give you very little control over the viewer UI.

Start with iframe

For simple inline display, <iframe> is usually the best first try. Modern guidance recommends it because it's the easiest to implement and generally the most compatible among the native options, as discussed in Anvil's guide to embedding PDFs in HTML.

<iframe
  src="/files/report.pdf"
  width="100%"
  height="700"
  style="border: 0;"
  title="Report PDF">
</iframe>

This works well when the file is served correctly and the browser supports inline PDF rendering. The server also needs to send the file with the application/pdf MIME type, or the browser may treat it like a generic download instead of a displayable document.

When embed is enough

<embed> is even shorter. If the browser handles PDFs natively, it'll render inline.

<embed
  src="/files/report.pdf"
  type="application/pdf"
  width="100%"
  height="700" />

Use this when you want minimal markup and don't care about fallback content. That's the main limitation. If the browser refuses to render the file inline, you don't get much room to explain what happened or offer alternatives.

Use object when you want fallback content

<object> is useful when you want a browser-native attempt first, plus HTML fallback if rendering fails.

<object
  data="/files/report.pdf"
  type="application/pdf"
  width="100%"
  height="700">
  <p>
    This browser couldn't display the PDF inline.
    <a href="/files/report.pdf">Download the PDF</a>.
  </p>
</object>

A common compatibility pattern is to nest an <iframe> inside <object>.

<object
  data="/files/report.pdf"
  type="application/pdf"
  width="100%"
  height="700">
  <iframe
    src="/files/report.pdf"
    width="100%"
    height="700"
    style="border: 0;"
    title="Report PDF">
  </iframe>
</object>

That gives supporting browsers a direct path and preserves a fallback route for others.

Here's a quick walkthrough if you want to see the pattern in action:

<iframe width="100%" style="aspect-ratio: 16 / 9;" src="https://www.youtube.com/embed/GOtFbGAF2xM" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>

Make it responsive

The most common mistake is treating the PDF like a fixed desktop widget. It usually looks fine on your laptop and then breaks your app layout on smaller screens.

Use a wrapper:

<div class="pdf-wrap">
  <iframe
    src="/files/report.pdf"
    title="Report PDF">
  </iframe>
</div>
.pdf-wrap {
  width: 100%;
  height: 75vh;
  min-height: 500px;
}

.pdf-wrap iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

Or use an aspect-ratio container if that fits your layout better:

.pdf-wrap {
  width: 100%;
  aspect-ratio: 4 / 3;
}

.pdf-wrap iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

Native tags are great for simple viewing. They're not great when you need predictable controls, uniform mobile behavior, or app-level features like search and annotations.

Gaining Full Control with JavaScript Viewers

The moment native embeds start fighting you, switch mental models. You're no longer “showing a file in a browser.” You're building a document experience inside your app.

That's where JavaScript viewers come in. The default open-source answer is PDF.js. It gives you rendering primitives and a viewer foundation, but you still have to decide how much UI you want to own. If your broader goal is converting or restructuring content rather than visually rendering it, a separate workflow like turning PDF content into HTML can also make more sense than embedding the original file.

Why teams switch to PDFjs

Teams usually move to PDF.js for four reasons:

  • Custom controls: your app needs its own zoom, pagination, or toolbar behavior.
  • Programmatic rendering: you want to render one page at a time instead of relying on the browser's viewer.
  • Text layer access: search, highlights, and copy behavior become part of your application.
  • Consistency: you'd rather own the rendering flow than depend on whatever Chrome, Safari, or a mobile browser decides to do.

That extra power comes with overhead. You now manage scripts, worker setup, rendering performance, layout, and state.

A basic PDFjs setup

This is the rough shape of a minimal setup. It renders the first page into a <canvas>.

<div id="pdf-container">
  <canvas id="pdf-canvas"></canvas>
</div>

<script type="module">
  import * as pdfjsLib from "https://cdn.jsdelivr.net/npm/pdfjs-dist@latest/build/pdf.min.mjs";

  pdfjsLib.GlobalWorkerOptions.workerSrc =
    "https://cdn.jsdelivr.net/npm/pdfjs-dist@latest/build/pdf.worker.min.mjs";

  const url = "/files/report.pdf";
  const loadingTask = pdfjsLib.getDocument(url);
  const pdf = await loadingTask.promise;
  const page = await pdf.getPage(1);

  const scale = 1.25;
  const viewport = page.getViewport({ scale });

  const canvas = document.getElementById("pdf-canvas");
  const context = canvas.getContext("2d");

  canvas.width = viewport.width;
  canvas.height = viewport.height;

  await page.render({
    canvasContext: context,
    viewport
  }).promise;
</script>

This is already more code than an <iframe>, and it still only renders one page. In return, you get actual control.

If you go this route, design for page-by-page rendering early. Don't render an entire large document into the DOM up front unless you're confident the device and browser can handle it. Also plan the UX deliberately. Once you own the viewer, users expect real app behavior, not a half-finished canvas with no loading state or keyboard support.

Build vs buy test: if your team wants a custom document UX, PDF.js is a strong base. If your team just wants the PDF to show up reliably, it may be more tool than you need.

Comparing Your PDF Embedding Options

The wrong choice here usually isn't a broken implementation. It's choosing a method that doesn't match the product requirement.

PDF Embedding Method Comparison

MethodEase of UseCustomizationPerformanceBrowser Consistency
Native tagsHighLowGood for simple inline viewingInconsistent, especially across devices
JavaScript librariesMedium to lowHighDepends on your rendering strategyMore consistent because you control the viewer
Third-party servicesMediumMedium to highOften easier to operationalizeDepends on the service and your integration

Use native tags when the PDF is a secondary element in the workflow. Think invoices, reports, or downloadable references where inline preview is enough.

Use a JavaScript library when the document is a product surface. That's common in review tools, knowledge apps, compliance systems, and any workflow where search, highlights, controlled navigation, or custom actions matter.

Use a service when your main problem is bigger than rendering. Teams often discover this later than they should. The HTML tag worked, but now they also need stable public links, private links, cache behavior, and file access rules.

The usability question most teams skip

A PDF can be embedded. That doesn't mean it should be the primary reading experience.

Nielsen Norman Group argues that PDFs are often poor for on-screen reading and recommends creating an HTML gateway page instead of forcing users into an in-browser PDF. It also notes that PDF is not accessible by default, and that text must be searchable, fonts must allow extraction, and form fields must be labeled properly. Their guidance leads to a practical best practice: use native embedding for convenience, but pair it with an accessible summary or alternative download path when the document is important, as explained in their article on avoiding PDF for on-screen reading.

That advice matters more on mobile, where screen space is tight and browser behavior is less predictable.

A good production choice often looks like this:

  • Inline preview for convenience
  • HTML summary for key content
  • Download link for guaranteed access

That combination respects both developer time and user reality.

Advanced Considerations for Production Apps

The easy part is getting a PDF to show up once. The actual work starts when the app has to behave predictably across devices, domains, and user states.

A comparison infographic detailing the pros and cons of embedding PDF documents within web applications.

Responsive layout and mobile fallback

A major gap in most embed pdf on html tutorials is that they stop at the tag and don't answer the compatibility question: what happens when mobile or older browsers don't render inline and trigger a download instead? Vendor guidance notes that mobile browser support is inconsistent, and that's where fallback behavior matters most, as noted in Nutrient's discussion of opening PDFs in web apps.

So build for failure, not just for the happy path.

  • Assume mobile may differ: desktop success doesn't prove mobile inline rendering will behave the same way.
  • Always provide an alternate action: add a visible download or “open in new tab” path near the embed.
  • Test the actual browsers your users have: don't stop after checking Chrome on a laptop.

CORS and file delivery

If your PDF lives on another domain, the browser may block it or behave inconsistently unless the file is served with the right cross-origin policy.

The symptom is usually confusing. The URL works directly in the browser, but fails or behaves oddly when embedded. That's because direct navigation and embedded fetching aren't the same thing.

A typical server response for a cross-origin PDF should include the correct content type and allow the requesting origin when appropriate.

Content-Type: application/pdf
Access-Control-Allow-Origin: https://your-app.example

If you don't control the upstream server, proxying the file through your own backend is often simpler than trying to debug partial browser support.

Treat PDF delivery like any other application asset. Content type, origin policy, and caching rules all affect whether the embed feels solid or flaky.

Security and user workflow

Native embeds don't give you much control over download behavior or viewer actions. If the document is sensitive, that matters.

A few practical rules help:

  • Keep private documents behind authenticated URLs: don't drop long-lived public links into the front end unless they're public.
  • Separate preview from access control: rendering a file and authorizing a user are different concerns.
  • Design around the task: if users are reviewing documents, not just reading them, the surrounding workflow matters as much as the embed itself.

If your app is document-heavy, the user experience around reading and annotation matters too. For teams thinking beyond display, this guide on how to improve your PDF note taking is useful because it focuses on how people interact with PDFs once they're on screen.

Example Using a Dedicated PDF Service OkraPDF

Sometimes the cleanest solution is to stop self-hosting PDFs for inline display and use a service that gives you a stable file URL first. That changes the problem from “how do I render this local file?” to “how do I embed a hosted asset reliably?”

A four-step infographic illustrating the streamlined process of uploading, hosting, and embedding PDF documents using OkraPDF services.

A typical workflow is:

  1. Upload a local PDF to a hosting endpoint.
  2. Receive a shareable hosted URL.
  3. Use that URL in your HTML embed.

Example request shape:

curl -X POST "https://api.okrapdf.com/host" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "file=@/path/to/report.pdf"

Example response shape:

{
  "file_url": "https://cdn.okrapdf.com/files/abc123/report.pdf"
}

The exact response fields depend on the API, so check the product docs before wiring this into production.

Embed the hosted PDF

Once you have a stable URL, the HTML stays simple:

<iframe
  src="https://cdn.okrapdf.com/files/abc123/report.pdf"
  width="100%"
  height="700"
  style="border: 0;"
  title="Hosted PDF">
</iframe>

This is the part many teams underestimate. Hosting is often the actual bottleneck, not the tag.

Use a signed URL when access matters

For private documents, use a time-bound or signed URL instead of exposing a permanent public path. That gives your backend a way to decide who can access the file and for how long.

A typical server-side flow looks like this:

const signedUrl = await createSignedPdfUrl({
  fileId: "abc123",
  expiresIn: "short-lived"
});

Then pass that signed URL into the same embed pattern.

If you want a developer-first way to host a PDF, get a shareable link, and build from there, OkraPDF is built for that workflow.


If you need to host PDF online, generate a pdf to link URL, or keep document delivery out of your app's critical path, OkraPDF is a practical place to start.