Get your API key
Migrate wkhtmltopdf to Playwright: options, fonts, and page breaks

Migrate wkhtmltopdf to Playwright: options, fonts, and page breaks

Migrate wkhtmltopdf to Playwright with a minimal rendering script, an option mapping table, font checks, and a rollout plan for existing PDF templates and apps.

5 min read

To migrate wkhtmltopdf to Playwright, replace the command-line invocation with a Chromium rendering script, map the print options, and review the output of real templates. The goal is document correctness, rather than identical line wrapping between two engines. Start with one self-contained invoice before migrating every export job.

The wkhtmltopdf project's status page explains the age and constraints of its Qt/WebKit foundation. If you are still choosing an engine, read wkhtmltopdf alternatives. This guide starts after that decision and focuses on moving existing templates.

Which wkhtmltopdf options have Playwright equivalents?

Paper size, margins, orientation, and repeated header/footer content have corresponding Playwright PDF settings. Several timing and layout options require a deliberate migration decision rather than a renamed flag.

wkhtmltopdf settingPlaywright destinationMigration check
--page-size A4format: 'A4'Check whether template CSS also declares a paper size
--orientation Landscapelandscape: trueVerify the actual page dimensions
--margin-top 15mmmargin: { top: '15mm' }Map all four margins explicitly
--print-media-typePrint media is the page.pdf() defaultReview print-specific styles
--footer-right '[page]/[topage]'footerTemplate with page placeholdersSupply footer styling and sufficient bottom margin
--javascript-delayAn explicit readiness conditionWait for the document's actual data or charts
--disable-smart-shrinkingNo equivalent flag to copyFix width and pagination assumptions in the template

Sources: wkhtmltopdf command options and Playwright PDF options.

Keep this mapping with the migration fixture. A missing margin can change every page break while leaving the document superficially plausible. Avoid accepting the first output merely because the browser returned a valid file.

What does a minimal migration script look like?

Use a static, self-contained HTML fixture first. The following script reads input.html, waits for its fonts and images, and writes an A4 document with explicit margins and a page-number footer. It assumes Playwright and its Chromium browser are installed.

Save this as render-pdf.mjs in the project containing the Playwright dependency:

import { readFile } from 'node:fs/promises';
import { chromium } from 'playwright';
 
const html = await readFile('input.html', 'utf8');
const browser = await chromium.launch({ headless: true });
 
try {
  const page = await browser.newPage();
  await page.setContent(html, { waitUntil: 'load' });
  await page.evaluate(async () => {
    await document.fonts.ready;
    await Promise.all(
      Array.from(document.images, (image) => image.decode())
    );
  });
  await page.pdf({
    path: 'output.pdf',
    format: 'A4',
    preferCSSPageSize: false,
    printBackground: true,
    margin: { top: '15mm', right: '10mm', bottom: '15mm', left: '10mm' },
    displayHeaderFooter: true,
    headerTemplate: '<div></div>',
    footerTemplate: '<div style="font-size:9px;width:100%;text-align:right;padding-right:10mm"><span class="pageNumber"></span>/<span class="totalPages"></span></div>',
  });
} finally {
  await browser.close();
}

Run it with node render-pdf.mjs. Inline images and fonts, or change the script to navigate to a controlled fixture URL. setContent() does not make relative references resolve against the directory containing input.html.

This is a static-template starting point. A chart or client-rendered document needs a readiness condition supplied by the application before printing. Our header and footer guide covers repeated-content details that need separate testing.

Why do fonts and page breaks change after migration?

Treat pagination as an acceptance item. Our recommended review checks font availability, table widths, print CSS, fixed-position elements, and repeated rows before adjusting the browser's scaling settings.

Use the actual fonts your documents require. A screenshot from a developer laptop does not establish what is installed in the rendering container. Keep the font files, template revision, and sample data in the migration fixture so reviewers can reproduce the output.

Test more than the short invoice that fits on one page. Include long company names, multiple tax lines, a table that crosses a page boundary, a missing optional field, and the writing systems your customers use. Our print CSS guide explains the layout controls to investigate when a row or heading lands on the wrong page.

Headers and footers deserve their own pass. Playwright documents that the print templates do not inherit main-page styles and do not execute scripts. A footer copied from wkhtmltopdf can therefore need inline styles even when the main document looks correct.

Use the HTML-to-PDF tool for a quick manual template check and PDF-to-PNG conversion for reviewing individual pages. Keep the automated acceptance run on the same renderer configuration you intend to deploy.

How do you roll out without breaking existing documents?

Our recommended rollout compares old and new renderers against a fixed fixture set, reviews intentional differences, and deploys the change with a known rollback artifact. Test content and layout separately: a readable total and a correct total are different requirements.

Record expected text, page count, dimensions, links, and page images for each important template. Review every page, including nearly empty final pages and footers. Freeze timestamps and sample identifiers so the comparison measures layout rather than changing data.

A new browser engine does not need to reproduce every quirk of the old engine. Mark deliberate improvements explicitly, then use those approved outputs as the next baseline. Do not automatically approve every difference just to make the migration check pass.

The operational choice remains: run Chromium yourself or use hosted rendering. With PDF4.dev, the hosted service handles the PDF render call; your team still owns template migration and acceptance. Our PDF generation best practices cover the surrounding job handling and deployment work.

Free tools mentioned:

Html To PdfTry it freePdf To PngTry it free

Frequently asked questions

Is Playwright a drop-in replacement for wkhtmltopdf?
No. Playwright controls Chromium through an API. Migrate the invocation, map print settings, review asset loading, and compare real output from your existing templates before switching production traffic.
How do wkhtmltopdf page size and margins map to Playwright?
Map page size to page.pdf format, orientation to landscape, and margins to the margin object. Decide whether CSS page size or explicit API options should take precedence.
Does Playwright use print CSS when generating PDFs?
Yes. The page.pdf documentation specifies print media by default. A screen preview can therefore differ from the generated document unless you inspect the print styling too.
Can I reuse wkhtmltopdf HTML headers and footers unchanged?
Review them before reuse. Playwright's headerTemplate and footerTemplate do not inherit the main page's styles and do not execute scripts. Use inline styling and the documented pageNumber and totalPages placeholders.
What replaces wkhtmltopdf javascript-delay?
Wait for an explicit application readiness signal and the assets your document requires. The sample covers a static HTML fixture; chart-based templates need a signal that chart rendering has completed.
How should I handle local images and fonts during migration?
Inline assets in a self-contained fixture or serve them from a controlled origin with correctly resolved URLs. The sample setContent call does not create a base URL for relative files.
Must the new PDF have the same binary hash as the old one?
No. Define acceptance through document content, page count, dimensions, and reviewed page images. Binary equality is not an appropriate migration target between rendering engines.
Can PDF4.dev replace the browser operation part?
PDF4.dev provides hosted HTML-to-PDF rendering. You still need to migrate template assumptions and verify output; the decision is whether your team also wants to operate Chromium workers.

Start generating PDFs

Build PDF templates with a visual editor. Render them via API from any language in ~300ms.