Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
You can avoid a headless browser in Node.js, but the right method depends on what “convert HTML to PDF” means for your project. For a layout you can build directly with JavaScript, use PDFKit to create the PDF without HTML. For existing HTML, a non-browser renderer such as html-pdf-lite can accept markup, but its CSS support is not equivalent to Chromium. If you need a PDF of a page that is already hosted, a hosted screenshot API is another option; that sends the rendering work to an external service rather than rendering your HTML string locally.
Choose the method that matches your input
“Without a headless browser” rules out tools that launch Chromium or another browser engine. It does not mean every alternative can faithfully print any website. The key choice is whether you need to preserve HTML or only produce a PDF with the same information.
| Approach | Input and output | Best fit | Main trade-off |
|---|---|---|---|
| PDFKit | JavaScript document operations produce a PDF stream | Invoices, receipts, reports, and layouts you can construct as PDF elements | You recreate the layout in PDFKit; it is not an HTML/CSS renderer. PDFKit project |
| html-pdf-lite | HTML string produces a PDF Buffer | Controlled templates where its supported layout and styling are sufficient | It is not a full Chromium renderer; complex layout and browser CSS fidelity are limited. Project repository |
| html-to-pdfmake with pdfmake | HTML is converted to a pdfmake document definition, which is then used to generate a PDF | A constrained HTML subset that maps to pdfmake’s document model | It does not promise arbitrary web-page rendering. Check current supported tags and styles in the package and pdfmake documentation. Package page |
| Hosted HTML-to-PDF API | Markup is sent over HTTP and PDF bytes are returned by an external service | Teams that prefer a service boundary instead of installing a renderer locally | Rendering depends on a network service and its current terms, availability, data handling, and pricing. pdfkitt Node.js page |
If you have an existing page whose appearance depends on modern CSS, first render representative documents with your candidate non-browser renderer. Test the elements that matter to your output: page breaks, fonts, images, tables, and layout. If browser-level fidelity is a hard requirement, the no-headless-browser constraint may be incompatible with the document.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problemsGenerate a PDF directly with PDFKit
PDFKit is the simplest fit when your content is structured data and you can define the document layout yourself. It produces PDFs through a document API and Node streams; it does not parse an HTML input document. The official getting-started guide documents installation, creating a PDFDocument, piping it to a writable stream, and calling end() to finish the file. See PDFKit’s getting-started guide.
#1 Best Overall
Install
In an existing Node.js project, install the package:
npm install pdfkit
The following ES module example creates a small PDF file. Use an environment configured for ES modules, or adapt the import to the CommonJS form documented by PDFKit.
import fs from 'node:fs';
import { PDFDocument } from 'pdfkit';
const doc = new PDFDocument();
const output = fs.createWriteStream('output.pdf');
doc.pipe(output);
doc.fontSize(18).text('Generated directly as a PDF');
doc.end();
await new Promise((resolve, reject) => {
output.on('finish', resolve);
output.on('error', reject);
});
Waiting for the writable stream’s finish event makes the example’s completion explicit before subsequent code treats the file as ready. Build the page by adding the text, images, and drawing operations your application needs. If your current source is HTML, PDFKit will not convert its tags or CSS for you: you must map the content and layout into PDFKit operations.
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 →When this route is a poor fit
- Your source is a complex HTML page and maintaining a second, manually recreated layout would be costly.
- The output must closely match browser rendering, including CSS-driven layout behavior that you have not recreated.
- Your application needs to accept arbitrary user HTML and render it unchanged.
Render an HTML template without Chromium
html-pdf-lite is a project-specific option for passing an HTML string to a non-browser renderer built on PDFKit. Its repository documents renderPdfFromHtml(html, options) returning a Buffer, so you can write those bytes to disk or handle them in memory. It is not a general Chromium substitute: the maintainers describe complex flexbox and grid support as partial and warn that browser CSS fidelity is not guaranteed. Check the repository’s current API and limitations before adopting it.
Rank #2
Install and run
npm install html-pdf-lite
import fs from 'node:fs/promises';
import { renderPdfFromHtml } from 'html-pdf-lite';
const html = '<h1>Invoice</h1><p>Amount due: $42</p>';
const pdf = await renderPdfFromHtml(html);
await fs.writeFile('invoice.pdf', pdf);
console.log('Wrote invoice.pdf');
This example uses a deliberately small HTML string. Start with a representative version of your actual template and verify the resulting PDF before putting the renderer into production. In particular, inspect pagination, fonts, images, tables, and any CSS features on which your layout depends. If a feature is unsupported or rendered differently, simplify the template, choose a different PDF-generation approach, or revisit the requirement to avoid a browser.
Scripts and untrusted markup
The project documentation says scripts are disabled by default and labels script execution unsafe. It warns against rendering untrusted HTML; enabling allowScripts can execute embedded scripts in the process. Keep scripts disabled unless you have a specific, reviewed need, and do not pass user-controlled markup to the renderer without an appropriate security design. Read the project’s security notes.
For either PDFKit or an HTML-accepting renderer, treat filesystem paths, fonts, and image sources as application inputs that need validation. PDFKit’s guide describes Node builds as having filesystem access and Node streams; it is not a security review of your particular deployment. PDFKit getting-started documentation.
Recommended Free Tools
Use html-to-pdfmake for a constrained document model
html-to-pdfmake offers a different bridge: convert HTML into a pdfmake document definition, then use pdfmake to generate the PDF. That can suit a constrained template whose tags and styles map to the document-definition model. It should not be treated as a way to print arbitrary web pages without checking support. The package page points readers to pdfmake documentation for supported features; consult those current references and test the precise markup and styles you plan to use. Package information.
Rank #3
Use a hosted API when the HTML is available to a service
A hosted HTML-to-PDF API can keep browser installation and rendering out of your Node deployment, but it introduces an external dependency. pdfkitt’s Node.js page describes sending HTML in an HTTP request and receiving PDF bytes. That is vendor-described behavior, not an independent evaluation; check the provider’s current terms, pricing, availability, limits, and data-handling practices before sending document content. pdfkitt Node.js page.
A hosted page-capture API is a related but distinct case: it captures a URL, not necessarily an arbitrary HTML string supplied by your application. For a private or dynamically generated document, confirm that the service can access the page and that its PDF options fit the result you need. Do not assume that a URL-capture API is a drop-in replacement for a local HTML-string renderer.
Performance, reliability, and cost
Do not generalize a package benchmark
The html-pdf-lite maintainers report a cold-start comparison of 86 ms for html-pdf-lite and 654 ms for Puppeteer in their repository. They describe the benchmark as run on Node 22, with A4 output and 15 warm iterations. These are project-reported measurements, not an independent benchmark, and they do not predict performance for your templates, hardware, or deployment. The same repository reports separate warmed results by sample template; those figures need their template and setup context to be meaningful. Benchmark details from the maintainers.
Free tools Windows power users keep installed
One-click scans. No signup required.
Measure the workload you will deploy
- Measure generation time for representative documents, including the largest templates you expect to process.
- Check memory use and concurrent jobs under your own runtime and deployment limits.
- Include assets such as fonts and images in tests; their availability and loading behavior can affect the finished document.
- Compare the operational burden of a local package with the network, data-handling, and service-availability dependency of a hosted API.
These are evaluation steps, not claims that one renderer is faster or more reliable for every workload. Package versions, API behavior, and vendor offers can change, so verify them when selecting a production dependency.
Rank #4
Troubleshoot common conversion problems
The PDF is missing or empty
With PDFKit, confirm that the document is piped to a writable stream and that doc.end() is called. In an application, handle stream errors and wait for the output stream to finish before reading or serving the file. With a Buffer-returning HTML renderer, confirm that the promise resolves and that the resulting bytes are written to the intended destination.
HTML appears, but the layout differs
This is a renderer capability issue, not necessarily a failed conversion. Reduce the template to a small reproduction, then check whether its layout depends on complex flexbox, grid, or other browser-specific behavior. Adjust the markup and CSS to the renderer’s supported subset, use direct PDF APIs for a controlled layout, or choose a browser renderer if fidelity is essential.
Page breaks, tables, or fonts look wrong
Use a production-like sample rather than relying on a single heading-and-paragraph test. Check how the renderer handles each specific feature, including the fonts and images your application supplies. If the output is unacceptable after adapting the template, the chosen non-browser renderer may not fit the requirement.
Windows 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 reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchRendering user-supplied HTML creates risk
Do not enable script execution casually. The html-pdf-lite maintainers warn against untrusted HTML and say script execution is unsafe. Keep scripts disabled by default and review or sanitize input according to your application’s threat model; sanitization alone should not be treated as proof that arbitrary markup is safe.
A hosted conversion request fails
Check the provider’s current request format, response handling, limits, and service status in its own documentation. Also verify that the service is permitted to receive the document and can access any URL or assets it needs. A network service adds failure modes that do not exist in a purely local PDF-generation flow.
Or skip the browser setup
If the page is published at a URL and a hosted capture suits your use case, ScreenshotNeo returns screenshots or PDFs from one GET request. This is URL capture, not a local conversion of an arbitrary HTML string. Its capture flow accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the shot; those steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the page verdict and billing status in headers. It also offers an MCP server with take_screenshot, get_page_info, and capture_pdf tools for AI agents. Learn about ScreenshotNeo.
For PDF output, set the output format using the current API documentation. The following Node.js request follows the provided API example and targets a hosted page:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
Check the response status and use the documented output-format options and response handling for your application; do not treat a URL capture as a way to submit a raw HTML string. See the ScreenshotNeo API documentation for the request details. The Free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for 1,000 free screenshots a month with no card.
Make the decision with a representative document
For a controlled report or invoice you can lay out yourself, PDFKit avoids HTML rendering entirely. For existing HTML, try a non-browser renderer only after checking its output against production-like templates and its supported CSS. For an HTML page already hosted at a URL, a hosted API can remove local renderer setup, provided its external-service trade-offs and access model suit the content. The decisive test is not whether a library accepts HTML; it is whether the resulting PDF meets the layout, security, deployment, and data-handling requirements of your application.
Frequently Asked Questions
Does PDFKit convert an HTML string to PDF?
No. PDFKit creates a PDF through JavaScript document operations; it does not parse HTML or CSS.
Can a URL screenshot API convert private, unsaved HTML?
Not by URL alone. A URL capture service needs a page it can access; it is distinct from passing an arbitrary HTML string to a local renderer.
Is html-pdf-lite pixel-perfect with Chrome?
No. Its maintainers say it is not a full Chromium renderer and browser CSS fidelity is not guaranteed.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

