webcapture Get a free key

wkhtmltopdf alternative for Java

On Java, the wrappers inherited the frozen binary, and openhtmltopdf takes a different toll: it only lays out well-formed XHTML, so templates needed normalizing before they printed at all. Playwright for Java retires both: page.pdf() prints the page as the browser shows it, modern CSS and web fonts included, and the normalization step disappears.

openhtmltopdf and flying-saucer render a CSS subset; wkhtmltopdf-java shells the dead binary. The first pair lays out offline but never runs JavaScript; the wrapper inherits the frozen engine wholesale.

Install

Add com.microsoft.playwright:playwright to the build, then run Playwright's install step once to download the browsers it drives.

What you keep: wrapper options become Pdf options

The wrapper options survive the trip. Page size becomes setFormat("A4"), orientation becomes setLandscape(true), margins become setMargin(), and setPrintBackground(true) keeps backgrounds.

What actually changes

The JVM wrappers exec'd the binary, and openhtmltopdf took a third road: laying out a well-formed XHTML subset in Java, which is why templates needed normalizing before they could print. Playwright for Java prints the page as the browser shows it, so the XHTML normalization step and the binary-on-PATH both leave the build, and fonts stop being a fontconfig exercise.

Before and after on a typical openhtmltopdf build:

Before, openhtmltopdf laying out a hand-prepared XHTML subset:

try (OutputStream out = new FileOutputStream("out.pdf")) {
    PdfRendererBuilder builder = new PdfRendererBuilder();
    builder.useFastMode();
    builder.withHtmlContent(xhtml, baseUri);
    builder.toStream(out);
    builder.run();
}

After, Playwright for Java printing with Chromium:

try (Playwright playwright = Playwright.create()) {
    Browser browser = playwright.chromium().launch();
    Page page = browser.newPage();
    page.navigate("https://example.com/report",
        new Page.NavigateOptions().setWaitUntil(WaitUntilState.NETWORKIDLE));
    page.pdf(new Page.PdfOptions().setPath(Paths.get("out.pdf"))
        .setFormat("A4").setPrintBackground(true));
}

setWaitUntil(WaitUntilState.NETWORKIDLE) waits for the page to finish before printing, and setPrintBackground(true) keeps background colors and images. The page lays out exactly as a browser shows it, so the XHTML normalization step disappears.

Verify before you cut over

Run your most fragile template through the after snippet above before you retire the old path, and compare page count, fonts, backgrounds, and page breaks against the current output. The smart-shrink compensations account for most of the delta; the rest are genuine engine differences to review.

OpenHTMLtoPDF or browser?

openhtmltopdf stays correct for XHTML-authored print documents: deterministic layout, no browser process, solid paged-media CSS. It never runs JavaScript and only accepts well-formed input, so anything client-rendered must use Chromium.

Frequently asked questions

Why does openhtmltopdf need XHTML?

It is not a browser: openhtmltopdf lays out a well-formed XHTML subset with its own CSS engine, so templates need normalizing before they print. Chromium prints the page as the browser already laid it out, and the normalization step goes away.

Do the Java wkhtmltopdf wrappers still work?

They run, but they exec the same binary that was archived on Jan 2, 2023, so their output is capped where the engine froze and no fix is coming.

Method

Checked 2026-09-11 against the openhtmltopdf user guide and the current Playwright for Java PDF documentation.


More languages: the Python migration guide, the PHP migration guide, the C# migration guide, the Go migration guide. The wkhtmltopdf alternatives hub holds the full flag table and the honest before-and-after notes.

Going deeper: the open-source comparison prices the self-hosted routes against hosted ones, the formatting guide covers what each engine class preserves, and the webcapture product page states the hosted route plainly.

Render your first page in seconds

Mint a key, POST a URL, and the finished document comes back in the same response; pass ?wait=false for a job ticket with poll and download URLs. The first 50 renders a month are free, and there is no credit card. Not ready for a key? The free URL to PDF tool renders public pages without one.