
I needed to convert a complex HTML invoice template to PDF last month. Tried the obvious approach first – File > Print > Save as PDF in Chrome. The output looked nothing like the original. Broken layouts, missing background colors, headers overlapping body text. Spent the next few days testing every free HTML to PDF method I could find, from browser tricks to command-line tools to online converters.
Here’s what I learned: the tool you pick depends entirely on what your HTML looks like. Simple pages with basic text? Chrome’s built-in print works fine. Complex layouts with CSS Grid, custom fonts, or JavaScript-rendered content? You need something more capable. If you’re working with PDFs regularly, check our best free PDF editors guide for editing them after conversion.
Quick Comparison: HTML to PDF Converters
| Tool | Type | CSS Support | JavaScript | Batch Convert | Max Pages | Cost |
|---|---|---|---|---|---|---|
| wkhtmltopdf | CLI (open source) | CSS 2.1 + some CSS3 | Yes (WebKit) | Yes | Unlimited | Free |
| Google Chrome Print | Built-in browser | Full CSS3 | Yes | No | Unlimited | Free |
| WeasyPrint | Python library | CSS3 (no JS) | No | Yes | Unlimited | Free |
| Puppeteer | Node.js library | Full CSS3 | Yes (Chromium) | Yes | Unlimited | Free |
| PDF24 Tools | Online | Good | Limited | Yes | No limit stated | Free |
| iLovePDF | Online | Basic | No | Yes (paid) | 25 MB file | Free (limited) |
| Sejda | Online + Desktop | Good | Limited | 3/day free | 200 pages | Free (limited) |
What Makes HTML to PDF Conversion Tricky
HTML is designed for screens that scroll. PDFs have fixed pages. That mismatch causes most conversion problems. A 3000px-tall webpage needs to be sliced into page-sized chunks, and the converter has to decide where those breaks happen. If it cuts through the middle of a table row or an image, the output looks broken.
CSS print media queries (@media print) help, but most web pages don’t include them. Background colors get stripped by default in many tools. Fonts that load from Google Fonts or Adobe might not embed properly. And JavaScript-rendered content (React apps, dynamic charts) simply won’t appear in tools that don’t execute JS.
1. wkhtmltopdf – Best Open Source CLI Tool
This has been the go-to command-line HTML to PDF converter since 2008. It uses an older WebKit rendering engine (the same one Safari was built on years ago) to render your HTML and output a PDF. I’ve used it in production systems generating 500+ invoices daily, and it handles that load without issues.
What I liked
- Handles 90% of real-world HTML pages correctly out of the box
- Executes JavaScript – so pages with jQuery, D3 charts, or simple dynamic content render properly
- Full control over margins, page size, headers, footers, and table of contents generation
- Runs on Windows, macOS, and Linux – download a single binary, no dependencies
- Processes URLs directly:
wkhtmltopdf https://example.com output.pdf
What’s not great
- CSS Flexbox and Grid support is spotty – it uses an older WebKit version from around 2012
- Custom web fonts sometimes don’t load unless you add a
--javascript-delay 1000flag - The project is officially archived on GitHub (last release 0.12.6 in January 2023) though it still works perfectly for most use cases
- No CSS custom properties (variables) support
Installation: Download from the releases page for your OS. On Ubuntu: apt install wkhtmltopdf. On macOS: brew install wkhtmltopdf. That’s it.
Basic usage:
wkhtmltopdf page.html output.pdf
wkhtmltopdf --margin-top 20mm --margin-bottom 20mm page.html output.pdf
wkhtmltopdf --enable-local-file-access ./invoice.html invoice.pdf
Best for: Developers running batch conversions on a server, CI/CD pipelines generating documentation, or anyone who needs repeatable PDF generation from templates. If your HTML uses modern CSS (Grid, Flexbox, custom properties), skip to Puppeteer below.
2. Google Chrome Print to PDF – Fastest for One-Off Pages
Every Chrome and Edge user already has this. Open any webpage or local HTML file, press Ctrl+P (Cmd+P on Mac), change the destination to “Save as PDF,” and hit save. Done. For a single page you need to convert right now, nothing beats the convenience.
What I liked
- Zero setup required – works with any HTML file you can open in a browser
- Full modern CSS support including Grid, Flexbox, custom properties, and animations (frozen at current state)
- JavaScript executes fully before the PDF captures the page state
- Respects @media print stylesheets if the page has them
- Headers and footers with page numbers are optional in the dialog
What’s not great
- Background colors and images are stripped by default – you need to check “Background graphics” in the print dialog every time
- No command-line automation without Puppeteer
- Page breaks happen wherever Chrome decides – you can’t control them without adding CSS
break-before: pagerules to your HTML - Multi-page documents sometimes clip content at the bottom of pages
- Custom margins require manual input each time
Pro tip: Before printing, open DevTools (F12) and run document.querySelectorAll('nav, header, footer, .sidebar, .ad').forEach(el => el.remove()) to strip navigation and ads. The resulting PDF will be much cleaner. You can also use Chrome’s Reader Mode (if available) for article-heavy pages.
Best for: Converting a single webpage or HTML file when you need the result in under 30 seconds. Not suitable for automation or batch processing.
3. WeasyPrint – Best for CSS-Heavy Documents
WeasyPrint is a Python library that converts HTML+CSS to PDF with excellent CSS3 support. Unlike wkhtmltopdf, it was designed specifically for document generation, so it handles things like page breaks, multi-column layouts, and print-specific CSS features properly. I switched to it from wkhtmltopdf for invoice generation and the output quality jumped immediately.
What I liked
- CSS3 support is excellent – Flexbox, custom properties, calc(), and most modern selectors work
- Native support for CSS Paged Media (page counters, running headers, named pages, margin boxes)
- Generates PDF bookmarks from heading tags automatically
- Embeds fonts properly – Google Fonts, local fonts, everything renders correctly
- Active development – regular releases, responsive maintainers
What’s not great
- No JavaScript execution at all – if your content is rendered by React/Vue/Angular, you need to pre-render it first
- No CSS Grid support (as of version 62) – this is a dealbreaker for some layouts
- Installation can be fiddly on Windows because it depends on Cairo and Pango libraries
- Slower than wkhtmltopdf for large documents – a 200-page report took 45 seconds vs 12 seconds
Installation:
pip install weasyprint
Usage example:
from weasyprint import HTML
HTML('invoice.html').write_pdf('invoice.pdf')
# Or from a URL:
HTML('https://example.com/report').write_pdf('report.pdf')
Best for: Python developers who need high-quality PDF output with precise CSS control. Ideal for invoices, reports, certificates, and any template-based document where you control the HTML source.
4. Puppeteer – Best for Modern Web Apps
Puppeteer controls a headless Chromium browser programmatically. Since it’s literally Chrome without a visible window, it renders HTML exactly like Chrome does – meaning full CSS3, JavaScript, web fonts, the works. If Chrome can display it, Puppeteer can PDF it.
What I liked
- Renders everything exactly as Chrome would – if the page looks right in your browser, the PDF will match
- Full JavaScript execution – React apps, dynamic charts, lazy-loaded content all render before PDF capture
- Granular control: custom page sizes, margins, header/footer templates with HTML, page ranges
- Can wait for specific elements to load before generating:
await page.waitForSelector('.chart-loaded') - Active Google-maintained project with weekly updates
What’s not great
- Downloads a 170+ MB Chromium binary on first install
- Memory-hungry – each conversion spawns a browser process using 200-400 MB RAM
- Requires Node.js knowledge – not a one-liner like wkhtmltopdf
- Slower startup time (~2-3 seconds to launch browser) makes it inefficient for single conversions
Installation:
npm install puppeteer
Usage example:
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('file:///path/to/page.html', {waitUntil: 'networkidle0'});
await page.pdf({
path: 'output.pdf',
format: 'A4',
printBackground: true,
margin: {top: '20mm', bottom: '20mm', left: '15mm', right: '15mm'}
});
await browser.close();
Best for: Developers converting JavaScript-heavy web applications to PDF. Also great for automated report generation where the source is a modern web dashboard. Overkill for simple static HTML pages.
5. PDF24 Tools – Best Free Online Converter (No Account)
PDF24 is the rare online tool with no daily limits and no registration requirement. Their HTML to PDF converter accepts both URLs and uploaded .html files. I’ve used it for quick one-off conversions when I’m on a machine without my usual dev tools installed.
What I liked
- No signup, no daily caps, no file size restrictions I could find
- Accepts both URLs and .html file uploads
- Output quality is decent – basic CSS renders correctly, fonts are preserved
- Files get deleted from their servers within one hour (German GDPR compliance)
- Also has a free desktop app for Windows with offline conversion
What’s not great
- JavaScript-rendered content doesn’t always appear – React/Vue apps produce blank PDFs
- Local file references (images, CSS) in uploaded HTML files won’t resolve since they’re not on PDF24’s server
- Can’t customize margins, page size, or orientation in the online tool
- Conversion speed varies wildly – took anywhere from 5 to 30 seconds for the same file on different days
How to use it: Go to pdf24.org, find “HTML to PDF” in their tools section, paste a URL or upload your .html file, click convert, download the result. That simple. If you convert HTML files with local image references, zip everything together and use their desktop app instead.
Best for: Quick conversions when you’re away from your development environment. Works well for converting blog posts, articles, and simple web pages. Not reliable for complex layouts or JS-heavy apps. For other PDF operations after conversion, see our guide to compressing PDFs if the output file is too large.
6. Sejda – Best for Batch URL Conversion
Sejda’s online HTML to PDF tool does something most others don’t – it handles batch URL conversion. Feed it 5 URLs, get 5 PDFs. The free tier gives you 3 tasks per day with files up to 200 pages or 50 MB each, which is generous enough for occasional use.
What I liked
- Batch conversion actually works – tested with 4 URLs simultaneously, all converted correctly
- Offers page size options (A4, Letter, Legal) and orientation toggle in the free tier
- Desktop app available for Windows, macOS, and Linux – works offline
- Good CSS rendering – handled a page with Flexbox layout correctly
- Output files are clean with no Sejda watermark
What’s not great
- 3 free tasks per day limit – resets every 24 hours
- Pages behind login walls obviously can’t be converted since Sejda can’t authenticate
- The desktop app costs $7.95/week for unlimited use – steep for a converter
- Uploaded HTML files lose their relative asset paths (same problem as PDF24)
Best for: Converting a handful of web pages to PDF when you need proper page sizing options without installing anything.
7. iLovePDF – Simplest Web Interface
iLovePDF is mostly known for its PDF editing tools, but they also have an HTML to PDF converter. It’s stripped down compared to others – paste a URL, get a PDF. No options, no settings to confuse you with. I found it useful specifically because of that simplicity when I just needed a quick conversion without thinking about parameters.
What I liked
- Dead simple – one input field, one button
- Captures full-page screenshots well for single-page sites
- Works on mobile browsers too if you need a conversion on your phone
- Fast processing – most URLs convert in under 10 seconds
What’s not great
- Limited free conversions before it asks you to sign up
- Can’t upload local HTML files – URL only
- CSS rendering is basic – missed some Flexbox alignments in my tests
- No control over page margins or headers/footers
- 25 MB file size limit on the free tier
Best for: Converting a public webpage to PDF when you literally just need it done in 10 seconds and don’t care about fine-tuning the output.
Which Tool Should You Actually Use?
After testing all of these, my recommendations boil down to:
You’re a developer building a system that generates PDFs: Use Puppeteer if your HTML uses modern CSS/JS, or WeasyPrint if you’re in Python and don’t need JavaScript rendering. Both integrate cleanly into existing codebases.
You need to convert HTML files from the command line: wkhtmltopdf. One binary, no dependencies, works on every major OS. The CSS3 limitations matter less than you’d think for most real documents.
You just want to save a webpage as PDF right now: Chrome’s Print to PDF. Already installed. Check the “Background graphics” box if colors are missing.
You’re on someone else’s computer and need an online tool: PDF24. No signup, no limits. If it doesn’t work for your page, try Sejda next.
Tips for Better HTML to PDF Conversion
Add Print Styles to Your HTML
If you control the source HTML, adding a print stylesheet solves most conversion problems before they happen:
<style media="print">
nav, footer, .sidebar, .no-print { display: none; }
body { font-size: 12pt; line-height: 1.4; }
a[href]::after { content: " (" attr(href) ")"; font-size: 9pt; }
img { max-width: 100%; page-break-inside: avoid; }
h2, h3 { page-break-after: avoid; }
table { page-break-inside: avoid; }
</style>
Handle Page Breaks
The CSS properties break-before: page, break-after: page, and break-inside: avoid work in all the tools I tested. Use them on section boundaries, tables you don’t want split, and image figures.
Embed All Assets
If you’re uploading HTML files to online converters, they can’t fetch your local images or CSS. Either use base64 data URLs for images or inline all your CSS. A tool like juice (npm package) or inliner can automate this.
Test with Chrome First
Chrome’s print preview is the fastest way to see how your HTML will look as PDF. If it looks wrong there, fix the HTML/CSS – don’t switch tools hoping for a better result. Most tools render similarly; the problem is usually in the source.
FAQ
Can I convert a whole website to PDF for free?
Not in one click. You’d need to crawl the site first (using wget or httrack), then batch-convert the downloaded pages. wkhtmltopdf can process multiple URLs in sequence: wkhtmltopdf page1.html page2.html page3.html combined.pdf outputs them as one PDF. For online tools, you’d need to convert each page individually. Expect 20-30 minutes of manual work for a site with 50+ pages.
Why does my HTML look different in the PDF?
Three common causes: (1) Background colors are disabled by default in most converters – enable “print backgrounds” or the equivalent option; (2) Web fonts aren’t loading because the converter can’t reach the font CDN or times out before they load; (3) Your layout uses CSS Grid or modern features that the converter’s rendering engine doesn’t support. Fix #1 with a flag, #2 by hosting fonts locally, #3 by switching to Puppeteer or Chrome Print.
Is there a way to convert HTML to PDF without losing formatting?
Puppeteer (headless Chrome) gives the closest match to what you see in your browser because it uses the exact same rendering engine. If the page looks correct in Chrome, the Puppeteer PDF output will be nearly identical. For static HTML without JavaScript, WeasyPrint produces excellent results with proper CSS Paged Media support. The key is matching your converter’s CSS engine capability to your HTML’s CSS complexity.
What’s the difference between wkhtmltopdf and Puppeteer?
wkhtmltopdf uses an older WebKit engine (circa 2012) – it’s fast, lightweight (single binary, no dependencies), and handles most HTML well. Puppeteer uses current Chromium – full CSS3, full JavaScript, but requires Node.js and downloads a 170 MB browser binary. Pick wkhtmltopdf for simple documents and server environments where you want minimal dependencies. Pick Puppeteer when your HTML uses modern CSS features or renders content with JavaScript frameworks.
Can I convert password-protected web pages to PDF?
Online converters can’t do this since they have no way to authenticate. With Puppeteer or wkhtmltopdf, you can pass cookies or authentication headers. Puppeteer can even fill in login forms programmatically before generating the PDF. Chrome Print to PDF works if you’re already logged in – you’re just printing what your browser currently shows. For our full list of PDF tools that handle various use cases, see the best free PDF editors roundup.