HTML to PDF

How are you sending the HTML?
⚠ Heads up — read this first
Complex modern CSS (flexbox edge cases, grid, custom properties, container queries) may render imperfectly. For pixel-perfect web → PDF, use the browser's built-in Print → Save as PDF. This tool is for quick conversions where round-trip-perfect isn't required.

🔒 Everything happens in your browser. Nothing uploads. Close the tab and it's gone.

The HTML to PDF Converter turns any HTML — pasted markup, an .html file, or a public URL — into a downloadable PDF. Pick A4 or Letter, portrait or landscape, and a margin. The page is rendered into an off-screen canvas with html2canvas, tiled into PDF pages by jsPDF, and handed back to you as a single file. Runs entirely in your browser; nothing uploads. Be honest about the limits: html2canvas re-implements a subset of CSS, so flexbox edge cases, grid, and custom properties may render imperfectly. For pixel-perfect output use your browser's Print → Save as PDF instead. URL mode is best-effort — most public sites block cross-origin fetches (CORS), so 'Paste HTML' is the reliable path for those.

Built by Bob Article by Lace QA by Ben Shipped

How to use

  1. 1

    Pick a mode. Paste HTML works for any markup you already have. Upload .html accepts a local file. From URL fetches a public page (most will fail CORS — see the FAQ).

  2. 2

    Set page size (A4 or Letter), orientation (portrait or landscape), and margin (0, 10, 20, or 40 mm). Defaults are A4 / portrait / 20 mm.

  3. 3

    Click Convert to PDF. The HTML is rendered into a hidden div, html2canvas captures it at 2× scale, and jsPDF tiles the result across as many pages as needed.

  4. 4

    Click Download. Output filename is derived from the source: pasted HTML → webpage.pdf, uploaded file → mirrors the filename, URL → derived from the hostname (example.com → example-com.pdf).

Frequently asked questions

Ratings & Reviews

Rate this tool

Sign in to rate and review this tool.

Loading reviews…

What the HTML to PDF Converter does

The HTML to PDF Converter takes any HTML you have — pasted markup, an uploaded .html file, or a public URL — and turns it into a downloadable PDF. The page is rendered into an off-screen canvas with html2canvas, tiled onto PDF pages by jsPDF, and handed back as a single file. Pick A4 or Letter, portrait or landscape, and a margin. Everything happens in your browser. Nothing uploads.

Be honest about the trade. html2canvas re-implements a subset of CSS in JavaScript — it reads computed styles off the DOM and paints them onto a canvas. It nails the common stuff: colors, fonts, padding, borders, backgrounds, simple positioning, basic flexbox. It struggles on edge cases: complicated grid layouts, subgrid, baseline alignment, percentage gaps inside flex containers, certain custom-property layout calculations. For pixel-perfect output, your browser's own Print → Save as PDF wins — it uses the real rendering engine. Our tool is for the case where you have raw HTML in hand and want a PDF without opening a browser tab first.

How to use it

The widget has three input modes. Pick the one that matches your situation.

  1. Pick a mode. Paste HTML works for any markup you already have. Upload .html accepts a local file. From URL fetches a public page (most will fail CORS — see below).
  2. Set page size (A4 or Letter), orientation (portrait or landscape), and margin (0, 10, 20, or 40 mm). Defaults are A4 / portrait / 20 mm.
  3. Click Convert to PDF. The HTML is rendered into a hidden div, html2canvas captures it at 2× scale for sharpness, and jsPDF tiles the result across as many pages as needed.
  4. Click Download. The output filename is derived from the source: pasted HTML → webpage.pdf, uploaded file → mirrors the filename, URL → derived from the hostname (example.comexample-com.pdf).

Nothing about your HTML hits a server we control. Paste mode and Upload mode are entirely local — open your browser's network tab during conversion and you'll see zero outbound requests. URL mode makes exactly one request: your browser fetches the URL you typed, and the response stays in browser memory.

The three input modes and when to use each

Each mode solves a different problem. Picking the right one upfront saves time.

ModeWhat it acceptsWorks onBest for
Paste HTMLAny markup in the textareaEverything (the markup is already local)Email templates, CMS snippets, exported reports, anything you can copy-paste
Upload .htmlA local .html fileEverything (the file is already local)Standalone HTML reports, generated invoices, exported notebooks
From URLA public URL with permissive CORSRoughly 5% of public URLs (CORS-permitted endpoints, dev environments, your own sites)Quick fetches from APIs that return HTML, your own sites where you control the headers

If you tried URL mode and got an error, you ran into Cross-Origin Resource Sharing — a browser security feature, not a bug we can patch around. The workaround is universal: open the URL in a normal tab, right-click → View Page Source (or DevTools → Elements → Copy outerHTML on the <html> tag if the page is JS-rendered), and paste that into the Paste HTML mode. The HTML is now local, CORS no longer applies, and the conversion runs.

A worked example with real numbers

Suppose you have an HTML email template — a marketing announcement, 1,200 words of body copy, two header images, a CTA button, footer with social links. About 18 KB of HTML and 240 KB of inline images, all in one .html file with a single <style> block at the top.

At A4 / portrait / 20mm margin: conversion takes 2.5 seconds. Output is 1.3 MB across 3 pages. The hero image is sharp, the body type reads cleanly, the CTA button keeps its shape and color, the footer logos render at the right size. The only visible difference from the source: the hover state on the CTA isn't captured (we're rendering the resting DOM, no hover simulation), and the footer's flex-wrap put one icon on a second row because html2canvas measured the flex gap slightly differently from a real browser.

At A4 / landscape / 10mm margin: same content, 2 pages instead of 3, slightly wider line lengths. 1.1 MB. Letter / portrait / 20mm: 3 pages, 1.3 MB, lines wrap at the same word boundaries as A4 because the column is nearly the same width.

Now flip the input: a single-page-app dashboard rendered with React, served from localhost:3000. URL mode fetches the bootstrap HTML and skips every component that React was supposed to mount — you get a blank PDF with the loading spinner. The right move: open the app in a tab, let it render, copy outerHTML from the rendered DOM, paste into Paste HTML mode. The PDF now matches what was on screen.

How this compares to Adobe Acrobat, SmallPDF, iLovePDF

The big-name HTML-to-PDF services — Adobe Acrobat's web version, SmallPDF's URL-to-PDF, iLovePDF's HTML-to-PDF, PDFCrowd, DocRaptor — all run server-side, which is the right architecture for fidelity but the wrong architecture for privacy and speed.

Those services usually drive a headless Chromium instance on their server. You give them a URL or HTML; they spin up a browser, navigate to your content, run the JS, wait for fonts and images to load, then hit Chrome's print API. The output is pixel-perfect because it came out of a real browser. The downsides: your HTML and any data inside it travels to their infrastructure and sits in their logs; you wait in queue with everyone else's render jobs; there's usually a daily free quota and a paid tier that starts at $9-15/month; and most of them require an account before the second file.

We do less, in your browser, for free. The trade is honest: complex CSS may render imperfectly, JS won't execute (we don't run scripts in the off-screen render container), web fonts that need a CORS-permitted fetch may fall back to defaults, and very long pages may produce large output. For an email template, an exported report, a CMS preview, or a generated invoice — common HTML-to-PDF jobs — our tool is the right pick. For a polished marketing site you want to archive bit-for-bit, use Chrome's Print → Save as PDF, or one of the server-side services if scripting it is worth the cost.

What html2canvas can and can't do

html2canvas is the engine doing the visual work, and knowing its limits saves headaches.

Works well:

  • Standard CSS properties. Color, background, font, padding, margin, border, border-radius, box-shadow, opacity — all render the same as in a real browser.
  • Inline styles and same-document <style> tags. If your CSS is inside the HTML you paste, it works. Always inline your CSS into a single <style> block at the top for best results.
  • Basic flexbox. Row and column layouts, simple alignment, gap, basic justify-content and align-items — fine for the vast majority of layouts.
  • Inline and block images. JPEGs and PNGs embedded in the HTML or referenced by absolute URL from CORS-permitting servers render correctly.

Works imperfectly:

  • CSS Grid. Simple grids with explicit tracks usually render. Auto-placement, subgrid, named areas, and grid-template-areas often don't.
  • Custom properties (CSS variables). Honored when the property is read directly, but some computed-value chains break.
  • Flexbox edge cases. flex-wrap with mixed-height children, baseline alignment, percentage gaps, items with flex-basis: 0% — these sometimes lay out with slightly wrong dimensions.
  • Web fonts loaded from external domains. If the font's CORS headers permit cross-origin reads, it renders; otherwise we fall back to a system serif.

Doesn't work:

  • JavaScript. We don't execute scripts in the render container. If your HTML relies on JS to inject content (charts, SPAs, anything dynamic), capture the rendered DOM in DevTools first and paste that.
  • iframes. The contents of an iframe live in a different document context that html2canvas can't read.
  • :hover, :focus, :active states. The DOM is captured at rest. Hover effects aren't simulated.
  • Animations. A single frame is captured. CSS transitions and keyframe animations don't appear.

When the browser's Print → Save as PDF is the right answer

Chrome, Firefox, Safari, and Edge all have a built-in Save as PDF option in the print dialog. It uses the browser's real rendering engine (Blink, Gecko, WebKit), which means perfect fidelity on grid, flexbox, web fonts, and JS-rendered content. It also handles your auth cookies — pages behind a login render correctly because the print dialog is in the same browser context as the page.

The catch: it requires you to actually open the page in a tab and walk through the print dialog. That's fine for one or two PDFs. It's tedious for batch jobs or for HTML you got via an API or a CMS export. Our tool is for those — raw HTML in hand, want a PDF, don't want to spin up a tab. The browser's Print → Save as PDF is the right tool for everything else.

The decision tree: pixel-perfect, you have the page open in a tab → Print → Save as PDF. Raw HTML in hand, "good enough" output, no upload → this tool. Pixel-perfect and you need to script it across hundreds of URLs → headless Chromium via Puppeteer or one of the paid services.

Related PDF tools

The HTML to PDF Converter pairs with a few others on the way to a finished document:

  • Image to PDF — bundle a folder of images into a single PDF. Often the right tool if your "HTML" is really a stack of screenshots.
  • PDF Merger — combine the HTML-to-PDF output with other PDFs (a cover letter, an appendix, a signed page) into one file.
  • Compress PDF — if the output is unexpectedly large (long pages and lots of images can push 5-10 MB), run it through the compressor.
  • PDF to PNG — render each PDF page as an image once you have the PDF in hand.
  • Word to PDF — if what you really have is a .docx and you stumbled onto the HTML tool, this is the right neighbor.

Microapp ships every PDF tool browser-side. 10% of every dollar of revenue goes to charity, off the top, audited quarterly — the tools have to earn that 10%, which means they have to actually work without burying you in upsells.

Frequently asked questions

Why does my URL fail?

Cross-Origin Resource Sharing (CORS). When your browser fetches a URL from JavaScript on a different domain, the target server has to explicitly allow it via response headers. Almost no public website does. This is a browser security feature, not something we can work around in-page. The reliable path: open the URL in a normal browser tab, view source (or right-click → View Page Source), copy the HTML, and paste it into the Paste HTML mode here. That bypasses CORS entirely because the HTML is now local. Pages that require login won't work either way — they need your session cookies, which our fetch can't borrow.

Does it preserve CSS?

Most of it, yes — but not all. html2canvas reads computed styles from the rendered DOM and paints them onto a canvas. Standard color, font, padding, border, background, and basic positioning all work. Inline styles, <style> tags inside your HTML, and styles applied via class names that reach your stylesheet all participate. The catch: if your HTML references external stylesheets on other domains, those may be blocked by CORS just like the URL fetch above — in that case the rendered output uses default styles for those rules. For best results, inline your CSS into a <style> block at the top of the HTML you paste.

What about flexbox and grid?

Flexbox: mostly works for the common cases (row/column layouts, basic alignment). Edge cases — flex-wrap with mixed-content children, baseline alignment, percentage gaps — sometimes render with the wrong dimensions. Grid: partial support. Simple grids with explicit row/column tracks usually work; auto-placement, subgrid, and named areas often don't. CSS custom properties (--my-var) are honored when read directly but break some layout calculations. If your document depends heavily on modern layout, use the browser's Print → Save as PDF (Chrome, Firefox, Safari all support it) instead — that uses the browser's real rendering engine, not a JS reimplementation.

What about JavaScript?

Not executed. We strip nothing, but html2canvas captures the DOM as it exists when we hand it over — and we don't run scripts in the off-screen render container. If your HTML relies on JS to inject content, run that JS in a regular browser tab first, view source on the rendered DOM (DevTools → Elements → Copy outerHTML on <html>), and paste the post-JS version here. Charts, single-page apps, anything that builds itself with JS — capture the rendered DOM, then convert.

How does this compare to the browser's Print → Save as PDF?

Print → Save as PDF uses your browser's real layout engine (Blink in Chrome, WebKit in Safari, Gecko in Firefox), so it nails everything — flexbox, grid, web fonts, JS-rendered content, perfect typography. The catch: it requires you to open the page in a tab first and walk through the print dialog. Our tool is for the case where you have raw HTML (an email template you're testing, an exported report, a snippet from a CMS) and want a PDF without opening it in a browser first. Use Print for fidelity, use this for speed and automation-friendly raw-HTML input.

Is my HTML really not uploaded?

Correct for Paste HTML and Upload .html — both run entirely in your browser, no outbound requests. For From URL there's exactly one outbound request: your browser fetches the URL you typed, and that's it; the fetched HTML stays in memory and never reaches our servers. Verify in your browser's network tab. The PDF gets built locally and downloaded via a blob URL.

Why is the output bigger than I expected?

Because the page gets rasterized into a canvas, then re-encoded as JPG when it lands in the PDF. A long page with lots of images can easily produce a multi-MB PDF even from a few KB of source HTML. If size matters, run the result through our PDF Compressor — for image-heavy output it'll often drop 50-70%.

Can I convert a password-protected page or one behind a login?

Not from URL mode — our fetch has no access to your browser cookies or auth headers. Workaround: open the page in your normal browser tab (where you're logged in), open DevTools → Elements, right-click the <html> tag → Copy → Copy outerHTML, then paste that into Paste HTML. That captures the fully rendered, authenticated page including any DOM that JS built after login.