The Best Tools to Convert HTML to PDF
Compare the best ways to convert HTML to PDF, from browser print to Puppeteer, Playwright, Acrobat, Adobe PDF Services, and ScreenshotNeo.
For a single page, use your browser’s Print → Save as PDF. For repeatable conversion, use Puppeteer or Playwright. Choose Acrobat when you need to capture multiple levels of a website or convert local HTML from a desktop workflow. Use Adobe PDF Services when HTML-to-PDF must be part of an application. If you need a hosted screenshot or PDF endpoint without maintaining a browser, ScreenshotNeo is the first service to try: it removes consent banners and other clutter before capture, bills only clean shots, and starts with a free monthly tier.
Choose a tool by the job
| Need | Best fit | Why |
|---|---|---|
| One page, no setup | Chrome Print | Open the page, print, and save as PDF. |
| Automated JavaScript workflow | Puppeteer | page.pdf() renders with print CSS and exposes PDF options. |
| Automated PDF with detailed controls | Playwright | Controls paper size, margins, ranges, backgrounds, and CSS page sizing. |
| Several pages or an entire site from a desktop app | Acrobat | Accepts URLs or local HTML and can follow multiple levels, paths, or servers. |
| Application or backend integration | Adobe PDF Services | Documents conversion from static or dynamic HTML, ZIP files, and URLs. |
| Hosted capture with cleanup and PDF output | ScreenshotNeo | Removes consent banners, popups, and chat widgets before capture; failed and non-clean captures are not billed. |
These are capability-based choices, not a benchmark. Output depends on the page’s CSS, fonts, scripts, images, and loading behavior.
1. Save HTML as PDF with Chrome
Chrome’s documented desktop flow is the fastest option for a one-off page:
- Open the HTML page.
- Press Ctrl+P on Windows/Linux or Command+P on macOS.
- Choose Save as PDF as the destination.
- Set paper size, orientation, margins, scale, and whether backgrounds print.
- Click Save and choose a filename.
See Chrome’s print instructions for the current desktop steps.
When browser print is enough
- You are converting one public page.
- You can inspect the preview manually.
- No server-side repeatability or batch processing is required.
Common browser-print problems
- Missing colors or images: enable background graphics and confirm the assets loaded before printing.
- Wrong layout: the page may define print-specific CSS. Inspect the print preview and adjust scale, margins, or orientation.
- Incomplete content: scroll through lazy-loaded sections first so the page has a chance to load them.
2. Convert HTML to PDF with Puppeteer
Puppeteer controls Chromium from Node.js. Its page.pdf() method generates a PDF using the print CSS media type by default. If you need the screen design, call page.emulateMediaType('screen') before generating the file. Read the official Page.pdf documentation for the complete option list.
Install
npm install puppeteer
Runnable Node.js example
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
});
try {
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 });
await page.goto('https://example.com', {
waitUntil: 'networkidle2',
timeout: 90000
});
await page.pdf({
path: 'example.pdf',
format: 'A4',
printBackground: true,
preferCSSPageSize: true,
margin: { top: '18mm', right: '14mm', bottom: '18mm', left: '14mm' }
});
} finally {
await browser.close();
}
})();
Useful Puppeteer options
| Option | Use |
|---|---|
format |
Standard paper size such as A4 or Letter. |
width, height |
Explicit paper dimensions. |
margin |
Top, right, bottom, and left margins. |
printBackground |
Include CSS backgrounds and colors. |
preferCSSPageSize |
Honor the document’s @page size. |
displayHeaderFooter, headerTemplate, footerTemplate |
Add generated headers and footers. |
pageRanges |
Export selected pages. |
landscape |
Use landscape orientation. |
Wait for a meaningful selector or an application-specific ready signal when networkidle2 is unreliable. Fonts and images must be loaded before PDF generation.
3. Convert HTML to PDF with Playwright
Playwright offers the same browser-rendering approach with Chromium, Firefox, and WebKit automation. Its page.pdf() method also uses print CSS by default and supports paper size, margins, ranges, backgrounds, and CSS page sizing. See the Page API documentation.
Install and run
npm install playwright
npx playwright install chromium
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch();
try {
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
await page.goto('https://example.com', { waitUntil: 'networkidle', timeout: 90000 });
await page.pdf({
path: 'example-playwright.pdf',
format: 'A4',
printBackground: true,
preferCSSPageSize: true,
margin: { top: '18mm', right: '14mm', bottom: '18mm', left: '14mm' }
});
} finally {
await browser.close();
}
})();
When to choose Playwright
- Your existing test or automation stack already uses Playwright.
- You need its browser and context controls for authentication, locale, timezone, or permissions before printing.
- You want explicit page ranges, backgrounds, and CSS page-size behavior.
4. Use Chrome Headless from the command line
For a small script or CI job, a headless Chrome installation can print a URL without writing application code. The available flags and behavior are documented in the Chrome Headless command-line reference.
google-chrome --headless --no-sandbox \
--print-to-pdf=page.pdf \
https://example.com
Use this when the URL is public and default browser settings are sufficient. For cookies, custom headers, waits, or per-page error handling, Puppeteer or Playwright is easier to control.
5. Convert web pages with Acrobat desktop
Acrobat can convert a URL or local HTML file and can capture multiple levels or an entire site. Its documented controls include staying on the same path or server, plus layout, encoding, bookmarks, tagged PDF structure, headers, and footers. See Adobe’s guides for web-page conversion and conversion settings.
- Open Acrobat and choose the web-page or URL conversion command.
- Enter a URL or select a local HTML file.
- Choose one page, multiple levels, or the entire site.
- Set path/server boundaries so the crawl does not leave the intended site.
- Configure page layout, encoding, bookmarks, tags, headers, and footers.
- Start conversion and review the resulting PDF.
Acrobat is practical for a human-managed desktop process. Confirm which options are available in your Acrobat version and plan before designing an automated workflow.
6. Integrate HTML conversion with Adobe PDF Services
Adobe PDF Services documents an HTML-to-PDF operation for static or dynamic HTML, ZIP input, and URL input. It is intended for application integration rather than an interactive desktop conversion. The documentation establishes supported inputs; it does not establish current pricing, quotas, retention, or service-level terms. Review the current Adobe PDF Services HTML-to-PDF documentation before committing to it.
7. Or skip the browser setup
ScreenshotNeo provides a hosted screenshot and PDF API. It accepts one GET request and can return PNG, JPEG, WebP, or PDF. The API supports full-page capture, lazy-image loading, CSS-selector element capture, dark mode, device presets, retina scale, PDF paper size, margins, landscape mode, page ranges, custom CSS and JavaScript, clicks, waits, blocked resources, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous jobs, webhooks, bulk capture, usage reporting, and an OpenAPI specification. See the ScreenshotNeo documentation for parameter details.
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}`);
Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers report the page verdict and whether the request was billed. An MCP server lets Claude, Cursor, and other MCP clients call take_screenshot, get_page_info, and capture_pdf. The Free plan includes 1,000 shots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.
Making PDFs reliable
Wait for the content you actually need
Network-idle signals can fire before a chart, web font, or lazy image is ready. Wait for a stable selector, a known application event, or a short delay after navigation. In browser automation, combine a navigation timeout with an explicit readiness check.
Control print CSS
@page {
size: A4;
margin: 16mm;
}
@media print {
.screen-only { display: none !important; }
a { color: black; text-decoration: none; }
.avoid-break { break-inside: avoid; }
}
Puppeteer and Playwright select print media by default. Use screen media only when the screen layout is intentional for the PDF.
Load fonts and images
- Use absolute, reachable asset URLs or embed critical assets.
- Wait for
document.fonts.readywhen typography matters. - Ensure images have stable dimensions to reduce layout shifts.
- Allow enough time for third-party charts and scripts, or replace them with server-rendered output.
Handle authentication and private pages
Use a browser context with the required cookies or an authenticated session. Do not put long-lived credentials in a URL. Hosted services require you to review their current data-processing terms before sending confidential HTML.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Blank PDF | Navigation failed or content is blocked. | Check the HTTP response, wait for a ready selector, and log browser console errors. |
| Only the visible viewport appears | Screenshot-style capture was used instead of PDF printing. | Use page.pdf() or the tool’s full-page/PDF option. |
| Backgrounds are missing | Print backgrounds are disabled. | Enable printBackground: true or the browser’s background option. |
| Screen layout differs from PDF | Print media CSS is active. | Inspect @media print; emulate screen media only when appropriate. |
| Content is cut between pages | Uncontrolled breaks or oversized elements. | Add break-inside: avoid, adjust margins, or split large components. |
| Fonts fall back | Font requests were not finished or are inaccessible. | Wait for document.fonts.ready and verify font URLs and permissions. |
| Timeouts in CI | Slow scripts, blocked resources, or insufficient browser resources. | Set an explicit timeout, block unnecessary requests, and capture diagnostics. |
| Different output across machines | Different browser, fonts, or OS rendering. | Pin the browser/runtime and install the same fonts in CI. |
Performance, reliability, and cost
- Browser startup: reuse a browser process for batches, while creating a fresh page or context per document.
- Asset weight: blocking analytics, ads, and unused media can reduce render time, but verify that required content is not removed.
- Concurrency: limit parallel pages to the CPU and memory available; too many Chromium pages cause contention and timeouts.
- Caching: cache PDFs only when the source and authorization policy allow it. In ScreenshotNeo, choose a cache TTL that matches how often the page changes.
- Retries: retry transient navigation failures with a bounded backoff. Do not blindly retry malformed URLs or authentication failures.
- Cost: local Chrome, Puppeteer, and Playwright have infrastructure costs rather than a per-conversion service fee. Hosted APIs have plan, quota, and data-handling terms that must be checked currently. ScreenshotNeo bills only clean shots; failed loads, blank pages, bot checks, timeouts, and cache hits are not billed.
FAQ
What is the easiest way to save one HTML page as a PDF?
Open it in Chrome, press Ctrl+P or Command+P, choose Save as PDF, and save the file.
Which is better for automated PDF generation, Puppeteer or Playwright?
Both expose browser-controlled PDF generation with print CSS defaults. Choose the one that matches your existing automation stack and required browser/context features.
Can JavaScript-generated HTML be converted?
Yes. Browser-based tools render the page before printing. Wait for the application’s content and fonts instead of relying only on navigation completion.
Should I use a hosted API for confidential HTML?
Review the provider’s current privacy, processing, and retention terms first. A local browser workflow keeps conversion in your own environment.
Can a PDF include only selected pages?
Playwright and Puppeteer expose page-range controls, and ScreenshotNeo supports PDF page ranges. Browser print dialogs may also offer page selection.
