webcapture Get a free key

wkhtmltopdf alternative for PHP

In PHP the archived binary arrives twice: snappy shells out to it, and the wkhtmltopdf-phar distributions are the same frozen executable reached from PHP. The replacement is Browsershot, which wraps Puppeteer: ->pdf() prints the same HTML with modern CSS and web fonts loaded from the page, and snappy's options translate method for method.

snappy and the wkhtmltopdf-phar binaries: snappy shells out to the dead binary, and the phar distributions are that same frozen executable reached from PHP.

Install

composer require spatie/browsershot, plus Node.js with Puppeteer beside PHP (npm install puppeteer gives Browsershot its browser). No wkhtmltopdf package anywhere in the image.

What you keep: snappy options become Browsershot calls

Snappy's options translate one to one. Page size becomes format("A4"), orientation becomes landscape(), margins become margins($top, $right, $bottom, $left), and "print-background" => true becomes showBackground(). Anything off this list is on the hub's flag table.

What actually changes

snappy is a thin shell over the same binary, and PHP deployments feel it hardest: the wkhtmltopdf executable had to exist inside the container, with every font package it needed installed beside it. Browsershot moves that out of the PHP image entirely, so the Dockerfile carries a browser instead of an archived package. The disable-smart-shrinking workarounds go with it.

Before and after on a typical snappy call:

Before, snappy shelling out to the archived binary:

use Knp\Snappy\Pdf;
$snappy = new Pdf("/usr/local/bin/wkhtmltopdf");
$snappy->generateFromHtml($html, "out.pdf", [
    "print-background" => true,
    "disable-smart-shrinking" => true,
]);

After, Browsershot printing with Chromium:

use Spatie\Browsershot\Browsershot;
Browsershot::url("https://example.com/report")
    ->waitUntilNetworkIdle()
    ->format("A4")
    ->showBackground()
    ->pdf("out.pdf");

The repairs live in two calls: waitUntilNetworkIdle() waits for the page to finish before printing, and showBackground() keeps background colors and images. Without adding dependencies you can also call the browser directly: chromium --headless=new --print-to-pdf=out.pdf https://example.com/report.

Verify before you cut over

Render your worst legacy template through the Browsershot call above while the old output still exists, and compare page count, fonts, backgrounds, and page breaks. The deleted smart-shrink workarounds explain most differences; anything left is a real layout change to review before the cut-over.

Native PHP or browser?

none: PHP has no maintained native renderer, so the replacement is the browser binary or a hosted API. Pure-PHP engines like dompdf, mPDF, and TCPDF parse a limited HTML subset with their own layout code, so they never reproduce a browser page; keep them only for documents authored for PDF.

Frequently asked questions

Does snappy still work?

Yes, until the binary it shells out to stops being installable: snappy is a thin wrapper around wkhtmltopdf, which was archived in 2023 and is disappearing from distro repositories.

What does Browsershot need on the server?

Node.js with Puppeteer, so the browser lives beside PHP instead of inside it: composer require spatie/browsershot plus an npm install of puppeteer, and no wkhtmltopdf package anywhere in the image.

Method

Checked 2026-09-11 against the snappy option reference and the current Browsershot documentation.


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

Going deeper: for the ops-free version of the same switch, the webcapture product page states the hosted engine and pricing on one page, the open-source comparison prices the self-hosted alternatives, and the formatting guide explains what the browser engine fixes.

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.