Puppeteer alternative for PDF generation

Replace Puppeteer for PDFs.
Keep your HTML.

Already using setContent() and page.pdf()? Send that HTML through the BladePDF Node.js SDK and receive a PDF from hosted Chromium. Your deployment needs Node.js 22+, an API key and outbound HTTPS; BladePDF runs the browser.

Official Node.js SDK No browser binary 200 renders free
invoice.ts typescript
import { BladePdf } from '@bladepdf/node';

const bladePdf = new BladePdf({
  apiKey: process.env.BLADEPDF_API_KEY!,
});

await bladePdf
  .fromHtml(html)
  .format('A4')
  .printBackground()
  .renderToFile('invoice.pdf');
HTML
stays yours
Assets
travel per request
Chromium
is managed
Migration scope

Start with one HTML-to-PDF endpoint.

An invoice endpoint that renders EJS or React to HTML is a straightforward candidate. The template stays in your application; the SDK submits its output and your PDF options to BladePDF.

A script that logs into a website, clicks through a dashboard and prints the result needs a different assessment. BladePDF does not expose Puppeteer's page-automation API. Keep that workflow in Puppeteer, or first make the application produce the final HTML directly.

Find the HTML source

Identify the final string passed to setContent(). Keep data loading, authorization and template rendering in Node.js.

Inventory the assets

A remote browser cannot reach your app's localhost. Attach local CSS, images and fonts from configured roots, or use URLs the service can reach.

Compare the output

Check page breaks, font weights, backgrounds and repeated headers with your longest document. Chromium versions and installed fonts can affect layout.

Before and after

Replace the render call.

Both examples read invoice.html from the working directory and save invoice.pdf. Install puppeteer for the first, or @bladepdf/node for the second, and run the saved .mjs file with Node.js.

Puppeteer — application-owned browser javascript
import { readFile } from 'node:fs/promises';
import puppeteer from 'puppeteer';

const html = await readFile('invoice.html', 'utf8');
const browser = await puppeteer.launch();

try {
  const page = await browser.newPage();
  await page.setContent(html, {
    waitUntil: 'networkidle0',
  });
  await page.pdf({
    path: 'invoice.pdf',
    format: 'A4',
    printBackground: true,
  });
} finally {
  await browser.close();
}
BladePDF — managed browser javascript
import { readFile } from 'node:fs/promises';
import { BladePdf } from '@bladepdf/node';

const apiKey = process.env.BLADEPDF_API_KEY;
if (!apiKey) throw new Error('Missing API key');

const html = await readFile('invoice.html', 'utf8');
const bladePdf = new BladePdf({ apiKey });

await bladePdf
  .fromHtml(html)
  .format('A4')
  .printBackground()
  .waitUntil('networkidle0')
  .waitForFonts()
  .renderToFile('invoice.pdf');
Implementation note. Use a self-contained invoice.html for this first check. The minimal SDK example does not grant local filesystem access; configure asset roots before using local CSS, images or fonts. Set BLADEPDF_API_KEY in the server environment. Rendering sends HTML and attached assets to BladePDF.
Puppeteer to BladePDF

Map the options your endpoint actually uses.

Copying the HTML is only the first step. These settings have direct equivalents; browser automation and network access require separate decisions.

Puppeteer BladePDF Node SDK Migration check
page.setContent(html) fromHtml(html) Render the template locally before calling either API.
format: 'A4', printBackground: true format('A4').printBackground() Compare output with the same print stylesheet and fonts.
margin: { top: '15mm', ... } margins({ top: 15, right: 12, bottom: 15, left: 12, unit: 'mm' }) Supply all four values. Check for competing @page CSS rules.
page.emulateMediaType('screen') emulateMedia('screen') Use print media for documents designed with @media print.
page.waitForFunction(expression) waitForFunction(expression) Keep a document-specific completion signal for charts or other asynchronous content.
headerTemplate / footerTemplate headerHtml(...) / footerHtml(...) Supply styles within the fragments and leave enough room in the page margins.
page.pdf({ path: 'invoice.pdf' }) renderToFile('invoice.pdf') For an HTTP download, use renderStream() instead of writing a temporary file.
page.goto(), clicks, interceptors, CDP No direct equivalent Keep Puppeteer for those operations or change the application to supply final HTML and assets.
Invoice INV-2026-1042 generated by the downloadable BladePDF Node.js example

Try the downloadable EJS invoice

The Node.js tutorial includes the full template, local CSS and SVG files, a package lock, and the PDF generated through the SDK. Use it to check the request and asset flow before adapting your own document.

Puppeteer vs BladePDF

What changes after the migration?

Both use Chromium, but matching HTML does not guarantee identical pagination across browser versions or font installations. Check output as well as the responsibilities below.

Capability Self-hosted Puppeteer BladePDF Node SDK
Runtime Node.js, Puppeteer, compatible Chrome, OS libraries, fonts, and writable runtime directories Node.js 22+ and the zero-runtime-dependency SDK; Chromium runs in BladePDF
Browser API General page automation and Chrome DevTools Protocol access Focused HTML-to-PDF options, readiness controls, assets, storage, and delivery
Concurrency Build a queue, cap pages, size memory, apply back pressure, and recover browser processes Use plan concurrency; excess short bursts can wait in the managed render queue
Serverless Package a compatible Chromium build and account for cold starts, bundle size, memory, and temp space Deploy the SDK and make an outbound API request; no browser binary in the function
Local assets Embed them, expose reachable URLs, or make the browser filesystem boundary explicit Attach referenced files from approved roots and rewrite their document references
Security Own the sandbox, egress, request interception, debugging endpoints, and untrusted HTML policy Use a constrained PDF API; BladePDF operates the isolated browser environment
Data boundary HTML and assets can remain fully inside your infrastructure HTML and attached assets are processed by the BladePDF service
Cost model Your compute plus engineering and operations time Hosted service plan based primarily on rendering capacity

This comparison covers HTML-to-PDF generation. Keep your own authorization, input validation, job records and failure handling around the SDK call.

Before switching

Check the constraints of your application.

BladePDF is a strong fit when

  • ✓ PDFs are required, but direct browser automation is not part of the feature.
  • ✓ Chrome packaging, cold starts, memory, crashes, or pool capacity complicate deployment.
  • ✓ You want typed Node.js delivery methods, managed async jobs, logs, and optional storage.
  • ✓ Your approved local assets should render without creating public URLs.

Keep Puppeteer when

  • → You need scraping, testing, screenshots, navigation, selectors, network interception, or arbitrary page scripting.
  • → Documents must render without an external network dependency.
  • → Policy requires render payloads to remain inside infrastructure you operate.
  • → You already have a reliable browser platform and value its low-level control.

BladePDF tradeoffs

  • ! Every render depends on network access to the BladePDF API.
  • ! The service processes document HTML and any attached assets or cloud-template context.
  • ! Plans have concrete concurrency, queue, payload, timeout, storage, and bandwidth limits.
  • ! A focused PDF API cannot expose Puppeteer's full browser automation surface.
FAQ

Questions teams ask before choosing the renderer.

Is BladePDF a complete replacement for Puppeteer?
No. BladePDF replaces a focused HTML-to-PDF workflow. Keep Puppeteer for scraping, testing, screenshots, navigation, selectors, request interception, or custom Chrome DevTools Protocol work.
Does BladePDF still use Chromium?
Yes. BladePDF renders with managed Chromium. The difference is that the browser binary, process lifecycle, isolation, capacity, recovery, and updates are outside your application deployment.
Can I keep EJS, Handlebars, Pug, Nunjucks, or React?
Yes. Render the template to HTML inside your Node.js application and pass the resulting string to fromHtml(). BladePDF does not replace your template engine.
Can the Node.js SDK return a stream?
Yes. Use renderStream() for a one-shot Node.js Readable, render() for a Buffer result, renderToFile() for atomic file output, or storePdf().submit() for a background render.
Do local images and fonts need public URLs?
No. Configure explicit documentRoot and searchRoots values and the SDK can attach referenced local files to the request. External URLs remain external and must be reachable by the renderer.
Does this work from AWS Lambda or Vercel Functions?
Yes, when the function can make an outbound HTTPS request and has enough duration for the render. The deployment does not include Chromium, which removes browser packaging and launch-time concerns from the function.

Try the migration with one invoice.

Use the free plan to compare your document's layout, asset handling and end-to-end response time before moving the rest of the workload.

npm install @bladepdf/node