What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
Use Puppeteer and headless Chromium when your source is HTML. It executes JavaScript, applies CSS, loads web fonts and uses the browser’s print layout engine. The basic flow is to launch Chromium, create a page, load an HTML string or URL, wait for your application’s data and assets, call page.pdf(), then close the browser. The resulting Uint8Array can be written to a file, object storage or an HTTP response.
Install the renderer and choose your input
Create a Node.js project and install Puppeteer:
npm install puppeteer
The package downloads (or uses) a compatible Chromium binary. In restricted containers or serverless environments, verify that Chromium and its required system libraries are available before deploying.
There are two common inputs:
- An HTML string: use
page.setContent()when your application generates the markup itself. - An existing webpage: use
page.goto()when the URL is the source of truth.
Puppeteer is appropriate when you need HTML/CSS layout, JavaScript execution, web fonts, images and browser pagination. A direct PDF library such as PDFKit is different: its documented API constructs text and graphics directly rather than rendering HTML. Do not treat PDFKit as an HTML renderer without adding and validating a separate conversion layer.
Generate a PDF from an HTML string
This complete ES-module example writes invoice.pdf:
#1 Best Overall
- Convert your PDF files into Word, Excel & Co. the easy way
- Convert scanned documents thanks to our new 2022 OCR technology
- Adjustable conversion settings
- No subscription! Lifetime license!
- Compatible with Windows 11, 10, 8.1, 7 - Internet connection required
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.setContent(`
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
@page { size: A4; margin: 18mm; }
body { font-family: Arial, sans-serif; color: #222; }
h1 { break-after: avoid; }
.card { break-inside: avoid; border: 1px solid #ddd; padding: 12px; }
@media print {
* { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}
</style>
</head>
<body>
<h1>Invoice</h1>
<p>Rendered from HTML in Node.js.</p>
<div class="card">Thank you for your business.</div>
</body>
</html>
`);
await page.pdf({
path: 'invoice.pdf',
format: 'A4',
printBackground: true,
margin: { top: '18mm', right: '18mm', bottom: '18mm', left: '18mm' },
});
} finally {
await browser.close();
}
Run it with a project configured for ES modules (for example, set "type": "module" in package.json) or adapt the imports to your project’s module system. page.pdf() returns a Promise<Uint8Array>; providing path makes Puppeteer write those bytes to disk.
Generate a PDF from an existing URL
Navigate before printing and choose a readiness condition appropriate to the site:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto('https://example.com/report', {
waitUntil: 'networkidle2',
});
await page.pdf({
path: 'report.pdf',
format: 'A4',
printBackground: true,
margin: { top: '18mm', right: '18mm', bottom: '18mm', left: '18mm' },
});
} finally {
await browser.close();
}
networkidle2 waits for a quiet network, but it cannot know whether your application’s API data, charts or images are logically ready. For dynamic pages, wait for a selector that your application adds after rendering, or wait for a deliberate delay only when you have no stronger readiness signal:
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.waitForSelector('[data-pdf-ready]', { timeout: 30000 });
// Optional only when a known animation or delayed asset needs it:
// await new Promise(resolve => setTimeout(resolve, 500));
await page.pdf({ path: 'report.pdf', format: 'A4', printBackground: true });
The official Puppeteer guide states that page.pdf() waits for fonts to load by default. Other assets still require a loading strategy owned by your application: make sure images, stylesheets, data requests and authenticated resources are reachable before printing.
Control print CSS, colors and pagination
Print media versus screen media
page.pdf() uses the print CSS media type. That means a stylesheet’s @media print rules apply, and screen-only rules may not. If the PDF must match the screen design, select screen media first:
await page.emulateMediaType('screen');
await page.pdf({ path: 'screen-style.pdf', printBackground: true });
If the PDF is intended as a print document, leave the default print media in place and define print-specific rules deliberately.
Rank #2
- Convert over 50 document file formats.
- Preview your files from Doxillion before converting them.
- Use batch conversion to convert thousands of files at once.
- Enjoy an easy-to-use, intuitive interface with a Drag and Drop file option.
- Burn your converted or original files directly to disc.
Paper size and margins
Use a named format such as A4, or specify dimensions with width and height. The @page rule controls CSS pagination; the PDF options control the browser’s output settings. Keep the two consistent to avoid surprising printable areas.
Recommended Free Tools
@page {
size: Letter;
margin: 0.7in;
}
Set landscape: true for wide tables or diagrams. Use explicit option margins when a caller or tenant can choose them.
Backgrounds and exact colors
Background graphics are omitted unless you set printBackground: true. Browsers modify colors for printing by default. When brand colors must remain exact, add:
* {
-webkit-print-color-adjust: exact;
print-color-adjust: exact;
}
Color reproduction still depends on the viewer and printer; this setting tells Chromium not to apply its normal print color adjustment.
Page breaks
Use modern break properties to keep logical units together:
.chapter { break-before: page; }
.keep-together { break-inside: avoid; }
h2 { break-after: avoid; }
For long tables, allow rows to split only when that is acceptable. Test headings, cards, signatures and footers at several content lengths; a rule that works for one invoice may produce a blank page for another.
Rank #3
- EDIT text, images & designs in PDF documents. ORGANIZE PDFs. Convert PDFs to Word, Excel & ePub.
- READ and Comment PDFs – Intuitive reading modes & document commenting and mark up.
- CREATE, COMBINE, SCAN and COMPRESS PDFs
- FILL forms & Digitally Sign PDFs. PROTECT and Encrypt PDFs
- LIFETIME License for 1 Windows PC or Laptop. 5GB MobiDrive Cloud Storage Included.
Return PDF bytes or stream them
Write the returned bytes yourself
Without a path, the PDF stays in memory as a Uint8Array. This is useful for object storage or an HTTP endpoint:
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.setContent('<h1>Hello</h1>');
const bytes = await page.pdf({ format: 'A4', printBackground: true });
// Example: res.type('application/pdf').send(Buffer.from(bytes));
} finally {
await browser.close();
}
For direct streaming, Puppeteer’s page.createPDFStream() returns a readable stream that can be piped to a response or storage destination. Set the response content type to application/pdf and handle back-pressure according to your web framework.
Production architecture and reliability
Reuse Chromium, isolate pages
Launching Chromium for every request adds startup work. For sustained throughput, keep a browser process alive and create a new page for each job. Close each page in a finally block, and recycle the browser periodically if your workload or hosting platform requires it. Never let one job’s cookies, DOM or JavaScript state leak into another.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallMake readiness explicit
- Wait for your application’s “data loaded” selector rather than relying only on network idleness.
- Ensure images have loaded and have usable dimensions; broken or blocked URLs create empty areas.
- Confirm external fonts and stylesheets are accessible from the runtime.
- Use a fixed timezone, locale or test data when deterministic output matters.
Deployment and cold starts
Containers and serverless functions must include a compatible Chromium binary and system libraries. Cold starts can be significant because a browser must be started before rendering; measure your own workload rather than assuming a universal duration. Limit concurrent pages to the memory available on the host.
Security boundaries
HTML is executable input. If users can submit markup or URLs, treat the renderer as a security boundary: restrict outbound network access, avoid placing credentials in page-visible HTML, isolate jobs, and do not expose internal services to arbitrary navigation. Sanitize untrusted content when your application’s threat model requires it.
Common failures and fixes
“Chromium executable not found” or launch failure
Cause: the deployment image lacks the browser or required libraries, or the configured executable path is wrong. Fix: install Puppeteer with its supported browser download, use a compatible system Chromium and set its executable path, or choose a runtime image that includes the required dependencies. Verify this in the same container used in production.
Rank #4
- Edit PDFs with Ease. Modify text, images, and layouts directly within your PDF documents.
- Convert & Organize. Export PDFs to Word, Excel, or ePub, and organize files with ease.
- Read & Annotate. Enjoy intuitive reading modes and powerful tools to comment, highlight, and mark up PDFs.
- Create & Manage PDFs. Create new PDFs, combine multiple files, scan documents, and compress for easy sharing.
- Fill & Sign Forms. Complete forms and digitally sign documents with secure e-signature tools.
The PDF is blank or missing application data
Cause: printing happened before client-side rendering completed. Fix: wait for a page-specific selector, data promise or other readiness signal after navigation. Capture console and page errors while diagnosing.
Styles or images are missing
Cause: relative URLs resolve against the wrong base, resources require authentication, or the runtime cannot reach them. Fix: use absolute URLs or a correct <base>, pass authentication through a controlled mechanism, verify network access, and wait for the assets your page needs.
Colors look washed out
Cause: Chromium’s print color adjustment or omitted backgrounds. Fix: set printBackground: true and use -webkit-print-color-adjust: exact where exact colors are required.
Layout differs from the browser window
Cause: the PDF uses print media, a different viewport, or different loaded fonts. Fix: call page.emulateMediaType('screen') for screen styles, set the viewport explicitly, define print CSS, and wait for fonts and data.
Pages split cards or headings awkwardly
Cause: CSS has no pagination hints or an element is taller than a page. Fix: apply break-inside: avoid, break-before and break-after selectively, then test with short and long content. An oversized element cannot always be kept intact.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsRequests hang indefinitely
Cause: a page keeps an open connection, a third-party script never finishes, or a selector never appears. Fix: set navigation and selector timeouts, use a bounded fallback, block unnecessary resources, and always close the page and browser in cleanup code.
Best Value
- ALL-IN-ONE SOLUTION – read, edit, convert, merge and protect your PDF files
- MAXIMUM FUNCIONALITY – create interactive forms, compare PDFs, bates numbering, find and replace text or colors, convert documents, OCR engine, comment, highlight, fill out and print forms, document protection and others
- EASY TO INSTALL AND USE – well-structured user-interface, in-program instructions, free tech support whenever you need it
- GREAT VALUE FOR MONEY - why spend a fortune if you can have maximum functionality at a reasonable price - this also fits the requirements of companies very well
Puppeteer or a direct PDF library?
| Concern | Puppeteer with Chromium | PDFKit-style direct construction |
|---|---|---|
| Source of truth | HTML and CSS | Drawing and text APIs |
| JavaScript execution | Yes, in a browser page | Not an HTML browser runtime |
| Pagination | CSS breaks plus browser print layout | Application-controlled coordinates and flow |
| Fonts and web assets | Loaded as browser resources | Added and positioned by the application |
| Deployment footprint | Chromium and system dependencies | Node library and its runtime dependencies |
| Streaming | Uint8Array or createPDFStream() |
Node stream output documented by the library |
Choose Puppeteer when fidelity to an existing web page matters. Choose a direct library when you want a small, fully programmatic document model and do not need browser layout.
Or skip the browser setup
If you need a hosted screenshot or PDF capture instead of operating Chromium yourself, ScreenshotNeo accepts one GET request and returns a PNG, JPEG, WebP or PDF. Its browser handles consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets; each cleanup step can be disabled. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads and cache hits are not billed, and the response reports the result with X-Page-Verdict and X-Billed headers. It also provides an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients.
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
const pdf = await res.arrayBuffer();
await import('node:fs/promises').then(fs => fs.writeFile('stripe.pdf', Buffer.from(pdf)));
See the complete option list and PDF parameters in the ScreenshotNeo documentation. You can also use cURL:
Free tools Windows power users keep installed
One-click scans. No signup required.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Or Python:
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)
Every feature is included on every plan. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Sign up free for ScreenshotNeo and use the hosted capture when maintaining browser infrastructure is not worth it.
FAQ
Does page.pdf() wait for web fonts?
Yes. Puppeteer documents that page.pdf() waits for fonts to load by default. You still need to manage application data and other assets.
Can I generate a PDF without saving a temporary file?
Yes. Omit path and use the returned Uint8Array, or use page.createPDFStream() for a readable stream.
Why does my HTML look correct on screen but not in the PDF?
The PDF uses print media by default. Check print rules, paper dimensions, margins, loaded fonts and asset readiness; use emulateMediaType('screen') only when screen styling is the intended output.

