How to batch convert HTML to PDF

20 July 2026

The fastest free way to batch convert HTML to PDF is a shell loop over headless Chrome: three lines, no installs, and your files never leave your machine. For recurring or high-volume batches, a script with a small concurrency pool against an HTML to PDF API scales further, and production pipelines graduate to async jobs with webhooks so the queue stops being your code.

Which of those three you need depends on one number: how many documents, how often. A folder of exported pages once? The loop. A nightly run of a few hundred statements? The script. Tens of thousands of invoices on the first of the month? The pipeline. This guide gives you working code for all three tiers, and explains why the freeware download sites that rank for this search are the worst of the options.

Key TakeawaysA folder of HTML files converts with a 3-line shell loop over headless Chrome: free, no installation, fully private. The freeware and upload-your-files sites ranking for this search add nothing except privacy risk and limits.The one dev script that ranks uses wkhtmltopdf, archived since 2023 with unpatched CVEs; loop over Chrome instead.In code, concurrency is the whole game: a pool of 5–10 parallel requests converts hundreds of files in minutes without tripping rate limits.At production scale, stop polling: async jobs return immediately, webhooks announce completion, idempotency keys make retries safe, and delivery can go straight to your own bucket.Privacy note: batch-uploading customer documents to a random online converter is a data-handling decision; treat it like one.

Batch convert a folder of HTML files (free, no install)

If a browser is installed, you already have a batch converter:

# Linux/macOS: every .html file in the current folder → matching .pdf
for f in *.html; do
  google-chrome --headless --no-pdf-header-footer \
    --print-to-pdf="${f%.html}.pdf" "$f"
done
# Windows PowerShell
Get-ChildItem *.html | ForEach-Object {
  & "C:\Program Files\Google\Chrome\Application\chrome.exe" `
    --headless --no-pdf-header-footer `
    --print-to-pdf="$($_.BaseName).pdf" $_.FullName
}

Rendering is real Chromium (headless mode docs), so modern CSS converts correctly, and everything happens locally. For dozens or even a few hundred files, run it and go get coffee; it's serial, but it's free.

Why not the freeware and online converters?

The search results for batch conversion are dominated by Windows freeware and upload-your-files websites. Three reasons to skip them: most wrap outdated engines (several are wkhtmltopdf-era, and the one developer script that ranks on GitHub uses wkhtmltopdf outright, an engine archived in 2023 with an unpatched 9.8-severity SSRF CVE); the online tools cap file counts and sizes until you pay; and, most importantly, batch-uploading documents (invoices, statements, anything with customer data) to an unknown third party's server is a data-processing decision that deserves more thought than a search click. The Chrome loop above does the same job with the engine you already trust.

Batch converting in code: the concurrency pool

When batches recur, you script them. The naive version fires every request at once (and hits rate limits) or one at a time (and takes forever); the right shape is a small pool:

// npm install p-limit
import fs from "node:fs/promises";
import pLimit from "p-limit";

const limit = pLimit(8); // 8 conversions in flight at once
const files = (await fs.readdir("./html")).filter((f) => f.endsWith(".html"));

await Promise.all(
  files.map((file) =>
    limit(async () => {
      const html = await fs.readFile(`./html/${file}`, "utf8");
      const res = await fetch("https://api.transformy.io/v1/pdf/chrome", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${process.env.TRANSFORMY_API_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ html, page_size: "A4" }),
      });
      if (!res.ok) throw new Error(`${file}: ${JSON.stringify(await res.json())}`);
      await fs.writeFile(
        `./pdf/${file.replace(/\.html$/, ".pdf")}`,
        Buffer.from(await res.arrayBuffer())
      );
    })
  )
);

Eight in flight converts a 500-file batch in a few minutes, error handling is per-file (one bad document doesn't sink the run), and the same pattern works in Python with asyncio.Semaphore. More Node-side detail, including the self-hosted Puppeteer equivalent and its production costs, lives in our Node.js HTML-to-PDF guide.

Production batches: async jobs, webhooks, and delivery

Past a certain volume, bulk HTML to PDF conversion outgrows the script itself: it has to stay alive for the whole run, retries double-convert documents, and every PDF makes a pointless round trip through your process on its way to storage. Production-grade batch conversion moves those three problems to the API:

Async jobs replace the open connection. Send "async": true and the response is a job ID immediately; the render happens on the API's queue, not your script's lifetime. Fire ten thousand requests in seconds and disconnect.

Webhooks replace polling. Register a webhook endpoint and each completed job announces itself, signed per the Standard Webhooks spec and retried with backoff if your receiver blips. No while not done: sleep(5) loop to babysit.

Idempotency keys make retries safe. Attach a key per document (the invoice number, say) and a retried request returns the original result instead of rendering, and billing, a duplicate. This is the difference between "re-run the failed half of the batch" being scary and being routine.

Storage delivery skips the round trip. A storage parameter uploads each finished PDF directly to your own S3, GCS, Azure, or R2 bucket; your infrastructure only ever handles job IDs and confirmations. The complete parameter set is in the HTML to PDF API docs.

Put together, the month-end run becomes: loop over invoices, POST async jobs with idempotency keys and a storage target, and watch webhook confirmations land. The queue, the retries, the browser fleet, and the bandwidth are all someone else's problem, which is the entire point of an HTML to PDF API at this tier.

FAQ

How do I convert multiple HTML files to PDF for free?

Loop over headless Chrome: for f in *.html; do google-chrome --headless --print-to-pdf="${f%.html}.pdf" "$f"; done. It's free, local, and renders with a current browser engine. No download or upload site required.

How do I batch convert thousands of HTML files to PDF?

Use an API with async jobs: submit each document as a job (with an idempotency key), receive webhook notifications as they complete, and have the PDFs delivered straight to your cloud bucket. A concurrency-pool script works into the hundreds; async pipelines are built for the thousands.

Can I batch convert without my files leaving my machine?

Yes: the headless Chrome loop is fully local, as is self-hosted Puppeteer. That's the right call for sensitive documents you're not ready to route through any third party, hosted APIs included; just budget for the browser being your operational responsibility.

Is there a Windows batch script for HTML to PDF?

The PowerShell loop above does it with installed Chrome: enumerate *.html, call chrome.exe --headless --print-to-pdf per file. No freeware needed.

Conclusion

To batch convert HTML to PDF, match the tier to the volume:

  • A folder, once → the headless Chrome loop. Three lines, private, free.
  • Recurring batches in the hundreds → a script with a concurrency pool of ~8 against a rendering API.
  • Thousands, on a schedule → async jobs + webhooks + idempotency keys + storage delivery; keep the loop, lose the queue-sitting.
  • Any tier → not wkhtmltopdf-based tools, and not anonymous upload sites for customer data.

The middle and top tiers cost cents per document: Transformy's free tier (100 documents a month, unlimited watermarked test renders) is enough to prove out the whole pipeline on your real files. Grab a key, point the pool script at your export folder, and time it against the serial loop; the difference is the business case.