# Puppeteer alternative for HTML to PDF

Puppeteer alternative for PDFs: compare Playwright, Gotenberg and hosted APIs, and map page.pdf() options to a simple JSON PDF API.

**Quick answer.** If you only run Puppeteer to make PDFs, send your HTML to a hosted Chromium API instead. You get the same print engine as `page.pdf()` without running a browser.

```bash
curl -X POST https://html-pdf.com/v1/pdf \
  -H "Authorization: Bearer $HTML_PDF_KEY" \
  -H "Content-Type: application/json" \
  -d '{"html": "<h1>Hello</h1>", "format": "A4"}' \
  -o out.pdf
```

Puppeteer is a great library. `page.pdf()` gives you Chrome's own print engine from Node.js, and a prototype takes about ten lines of code. The trouble starts when PDF generation becomes a production service that has to stay up.

This page explains why teams stop self-hosting Puppeteer for PDFs, what the realistic options are, and how to move existing `page.pdf()` calls to an API.

## Why teams move away from self-hosted Puppeteer

Here are the problems that usually push teams to look elsewhere. None of them are bugs in Puppeteer. They come from running a full browser inside your app.

- **Chromium is heavy.** The `puppeteer` package downloads a Chrome build on install, and in Docker you also need the system libraries and fonts Chrome expects. Images get big and builds get slow.
- **Memory spikes.** Each page is a renderer process. A long report or a page full of images can use hundreds of megabytes, and a burst of parallel requests can take a small container down.
- **Zombie processes.** If your code throws before `browser.close()`, or a page hangs, Chrome processes keep running. Teams end up writing pools, timeouts and watchdogs around the browser.
- **Serverless limits.** AWS Lambda caps an unzipped deployment package at 250 MB. You need a trimmed build such as `@sparticuz/chromium`, plus enough memory and timeout to cover cold starts.
- **Security of untrusted HTML.** If users or AI agents control the HTML, a browser on your network can be pointed at `file://` paths or internal addresses like cloud metadata endpoints. Rendering untrusted HTML safely means sandboxing and blocking private networks yourself.

## The options

This table compares the four realistic ways to produce Chromium-quality PDFs.

| | Puppeteer (self-hosted) | Playwright (self-hosted) | Gotenberg (self-hosted) | Managed PDF API (html-pdf.com) |
|---|---|---|---|---|
| What it is | Node.js library driving Chrome | Library for Node.js, Python, Java, .NET | Docker image with an HTTP API around Chromium and LibreOffice | Hosted HTTP API |
| PDF engine | Chromium | Chromium (PDF is Chromium-only) | Chromium | Headless Chromium via Gotenberg |
| You run a browser | Yes | Yes | Yes, inside one container | No |
| Languages | JavaScript/TypeScript | Several | Any (HTTP) | Any (HTTP) or MCP |
| Cost | Your servers | Your servers | Your servers (MIT licensed) | Per page, credits never expire |
| Best for | Full control in Node.js | Teams already using Playwright | Self-hosting without writing browser code | Not running PDF infrastructure |

**Playwright** has the same `page.pdf()` model and the same operational problems. It does have a nicer API and support for more languages. See [Playwright HTML to PDF](https://html-pdf.com/playwright-html-to-pdf).

**Gotenberg** moves the browser into a dedicated container you call over HTTP. That solves process management and language lock-in, but you still host, scale and patch it. See [self-host Gotenberg with Docker](https://html-pdf.com/self-host-gotenberg-docker).

**A managed API** removes the browser from your stack entirely.

## When Puppeteer is still the better choice

Puppeteer still wins in a few cases. Keep it if any of these apply.

- **You need browser automation before printing**, like logging in, clicking through a flow, or filling forms, and then saving the result.
- **The HTML lives on a private network** that an external service can't reach.
- **Volume is very high and steady**, so a well-tuned browser pool on your own hardware costs less than per-page pricing.
- **You need features we don't offer**, such as screenshots (PNG), PDF outlines or tagged PDFs.

## Or skip the server

This section shows how a `page.pdf()` call looks after moving to html-pdf.com. We run Chromium for you. You send HTML or a public URL and get a PDF back, with the same print engine as `page.pdf()`.

```js
// Before: Puppeteer
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(html, { waitUntil: "networkidle0" });
const pdf = await page.pdf({
  format: "A4",
  printBackground: true,
  margin: { top: "20mm", right: "15mm", bottom: "20mm", left: "15mm" },
  displayHeaderFooter: true,
  headerTemplate: "<span></span>",
  footerTemplate: '<div style="font-size:9px;width:100%;text-align:center">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>',
});
await browser.close();
```

```js
// After: html-pdf.com (Node.js 18+, no browser)
import fs from "node:fs/promises";

const res = await fetch("https://html-pdf.com/v1/pdf", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.HTML_PDF_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    html,
    format: "A4",
    print_background: true,
    margin: { top: "20mm", right: "15mm", bottom: "20mm", left: "15mm" },
    footer_html: '<div style="font-size:9px;width:100%;text-align:center">Page <span class="pageNumber"></span> of <span class="totalPages"></span></div>',
  }),
});
if (!res.ok) throw new Error(await res.text());
await fs.writeFile("out.pdf", Buffer.from(await res.arrayBuffer()));
```

### page.pdf() options to JSON options

| Puppeteer | html-pdf.com |
|---|---|
| `page.setContent(html)` | `"html": "..."` |
| `page.goto(url)` | `"url": "https://..."` (public pages only) |
| `format: "A4"` | `"format": "A4"` (A3 to A6, Letter, Legal, Tabloid) |
| `width` / `height` | `"width"` / `"height"`, e.g. `"210mm"` |
| `landscape: true` | `"landscape": true` |
| `margin: {top, right, bottom, left}` | `"margin"`: `"10mm"` or `{top, right, bottom, left}` |
| `printBackground: true` | `"print_background"` (defaults to `true`) |
| `preferCSSPageSize: true` | `"prefer_css_page_size": true` |
| `scale` | `"scale"` (0.1 to 2) |
| `pageRanges: "1-3"` | `"page_ranges": "1-3"` |
| `displayHeaderFooter` + `headerTemplate` / `footerTemplate` | `"header_html"` / `"footer_html"` (classes `pageNumber`, `totalPages`, `date`, `title`; leave room with `margin`) |
| `page.emulateMediaType("screen")` | `"media": "screen"` |
| `page.waitForFunction("window.ready")` | `"wait_for_expression": "window.ready === true"` |
| `waitForTimeout(2000)` | `"wait_delay": 2` (0 to 10 seconds) |
| `path: "out.pdf"` | `"filename": "out.pdf"`, or `"response": "url"` for a 24-hour link |

Puppeteer can load local images and fonts from disk, but an API can't. Use absolute `https://` URLs, inline data URIs, or a multipart request with `index.html` plus asset files and an `options` JSON field.

Add `"max_pages": 20` to fail runaway documents without being charged.

For AI agents, the [remote MCP server](https://html-pdf.com/pdf-mcp-server) at `https://html-pdf.com/mcp` exposes `html_to_pdf` and `url_to_pdf`. Claude, ChatGPT or Cursor can then create PDFs without any code.

## Pricing

Here is what it costs. 1 credit = 1 PDF page. You get 100 free credits once you confirm your email, then packs from $10 for 1,000 pages down to $250 for 50,000 ($0.005 per page).

Purchased credits never expire, auto top-up is optional, and failed renders are free. Limits are 20 MB per request, 30 s per render and 120 requests per minute.

```bash
curl -X POST https://html-pdf.com/v1/signup -H "Content-Type: application/json" -d '{"email": "you@example.com"}'
# Then open the link we email you to confirm (adds the 100 free credits)
```

[Get a free API key](https://html-pdf.com/login) · [API docs](https://html-pdf.com/docs) · [Puppeteer HTML to PDF guide](https://html-pdf.com/puppeteer-html-to-pdf) · [HTML to PDF in Node.js](https://html-pdf.com/html-to-pdf-nodejs)

## FAQ

### What is the best alternative to Puppeteer for generating PDFs?

If you want to keep running the browser yourself, Playwright or Gotenberg are the closest options. If you don't want to run any PDF infrastructure, a hosted Chromium API like html-pdf.com gives the same output from one HTTP call.

### Does html-pdf.com produce the same PDFs as Puppeteer page.pdf()?

Yes, it renders with headless Chromium, the same print engine behind `page.pdf()`. Most options map one to one, for example `printBackground` becomes `print_background` and `footerTemplate` becomes `footer_html`.

### Can I convert a page behind a login without Puppeteer?

The API only reaches public URLs. For private pages, render the HTML on your own server and send it in the `html` field instead of `url`.

### How much does a Puppeteer alternative API cost?

html-pdf.com charges 1 credit per PDF page, with 100 free credits once and no card required. Packs range from $10 for 1,000 pages to $250 for 50,000, purchased credits never expire, and failed renders cost nothing.
