HTML To PDF Converter
18 February 2026

Stop Bundling Puppeteer. Use an API.

Chromium binaries that break on every deploy, 400 MB added to your Lambda, and a different font-rendering bug on every OS. There's a better way — and it costs $5 a year.

You've been there. The invoice feature works perfectly in local dev. You push to production, and suddenly Puppeteer can't find the Chromium binary. So you add puppeteer-core and a Lambda layer. Now your cold start is 8 seconds. You add caching. The cache gets stale. You add cache invalidation. And somewhere in the middle of all this, you've written 400 lines of infrastructure code to generate a PDF.

It didn't have to be this way.

The actual cost of self-hosting Puppeteer

Let's be honest about what running Puppeteer in production actually involves:

  • Binary bloat: Chromium is ~170–400 MB depending on how you package it. That's your Lambda layer budget gone.
  • Environment fragility: fonts render differently on Alpine Linux than on macOS. Good luck debugging that on a deadline.
  • Memory pressure: Chromium leaks. You need to manage browser instances, page pools, and teardown carefully — or watch your server quietly OOM at 3am.
  • Security surface: Running a full browser process in your backend is a meaningful attack surface. Sandbox configuration alone is a rabbit hole.
  • Maintenance: Puppeteer version bumps break things. Chromium updates break things. Your Node version breaks things.

None of this is your actual problem. Your actual problem is: a user clicked "Download Invoice."

What the API approach looks like instead

One POST request. Your HTML in. A PDF URL out.

const res = await fetch('https://htmltopdfconverter.com.au/api/programmatic/pdf/generate', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'text/html',
  },
  body: renderToStaticMarkup(<InvoiceTemplate data={invoice} />),
});

const { pdfs } = await res.json();
// pdfs[0].url — done.

No browser process. No Lambda layer. No cold start penalty. No memory leak. No font mystery. The rendering is done by a real Chromium instance on our end — you just don't have to babysit it.

What it costs

$5 AUD per year. Flat. No per-page fees. No tier unlocks. No "contact sales."

That's the cheapest option available, full stop. Most alternatives charge per-page, per-seat, or have a monthly floor that costs more than your entire infrastructure budget for a side project. We charge a flat $5/year because we're not trying to extract maximum revenue from a utility.

You also get: actual support (email us, we respond), and we're actively open to feature requests. If there's something you need — specific PDF options, webhook callbacks, batch endpoints — tell us. Small team, short feedback loop.

When this isn't the right fit

If you're generating hundreds of PDFs per second at high concurrency, you'll hit the rate limit (10 req/min per user) and should probably run your own infrastructure. But if you're building a SaaS, an internal tool, or automating document delivery for a client — this is the right call.

The math is simple: how many hours have you already lost to Puppeteer? Now multiply that by your hourly rate. Five dollars is a rounding error.

Sign up, grab an API key from your dashboard, and send your first request in under 10 minutes. Full docs here.

FAQ

What rendering engine do you use?

A real Chromium instance — the same engine Puppeteer wraps. What you see in Chrome is what you get in the PDF. Full CSS support including backgrounds, custom fonts, flexbox, grid.

Can I send React-rendered HTML?

Yes. Use renderToStaticMarkup (or equivalent) server-side, then POST the resulting HTML string. We render what we receive — there's no client-side JS execution on our end.

What's the rate limit?

10 requests per minute per user. Generous for any normal document generation workload. If you have a legitimate use case that exceeds this, contact us and we'll talk.

What if I have a feature request?

We want to hear it. Use the contact page or email us directly. We're a small team and we actually act on good suggestions.