webcapture Get a free key

wkhtmltopdf alternative for Go

In Go, drive Chromium directly over the DevTools protocol: chromedp's page.PrintToPDF command prints the same HTML with modern CSS and web fonts loaded. The wkhtmltopdf flags become print parameters, and the smart-shrinking workarounds have no successor to migrate.

go-wkhtmltopdf shells the dead binary; chromedp talks to Chrome directly over the DevTools protocol. The wrapper inherits the frozen engine; chromedp drives the real thing.

Install

go get github.com/chromedp/chromedp. chromedp drives an installed Chrome or Chromium over the DevTools protocol, so the runtime needs a Chrome binary and nothing else.

What you keep: exec flags become print parameters

The exec flags land on the PrintToPDFParams struct as plain fields. Page size becomes PaperWidth and PaperHeight in inches, orientation becomes Landscape: true, margins become the MarginTop, MarginBottom, MarginLeft, and MarginRight fields, and PrintBackground: true keeps backgrounds.

What actually changes

go-wkhtmltopdf is an exec call: a binary on PATH, temp files for input and output, and a hard dependency on a package most distros have stopped shipping. chromedp speaks the DevTools protocol to a real Chrome, so the render becomes bytes in memory and the static binary you ship stays static.

Before and after on a typical go-wkhtmltopdf call:

Before, go-wkhtmltopdf exec-ing the archived binary:

pdfg, _ := wkhtmltopdf.NewPDFGenerator()
pdfg.AddPage(wkhtmltopdf.NewPage("https://example.com/report"))
pdfg.PageSize.Set("A4")
if err := pdfg.Create(); err != nil {
    log.Fatal(err)
}
pdfg.WriteFile("out.pdf")

After, chromedp printing with Chromium:

ctx, cancel := chromedp.NewContext(context.Background())
defer cancel()
if err := chromedp.Run(ctx,
    chromedp.Navigate("https://example.com/report"),
); err != nil {
    log.Fatal(err)
}
printBackground := true
res, err := chromedp.Call(ctx,
    page.PrintToPDF,
    page.PrintToPDFParams{PrintBackground: &printBackground},
)
if err != nil {
    log.Fatal(err)
}
if werr := os.WriteFile("out.pdf", res.Data, 0o644); werr != nil {
    log.Fatal(werr)
}

The navigate action waits for the load event before the print runs, and PrintBackground: true keeps background colors and images. The exec call, the binary on PATH, and the temp files all disappear.

Verify before you cut over

While the old binary still runs, render your worst template through chromedp and through go-wkhtmltopdf, and diff the results: page count, fonts, backgrounds, page breaks. The deleted shrink workarounds explain most differences, and what remains is a short list of real layout changes to sign off.

Gotenberg or in-process?

Gotenberg is the ops-heavy-but-free middle: same Chromium, REST in front. One container serves every language and takes the browser lifecycle out of your binary; the cost is operating the service. In-process chromedp wins when rendering belongs inside the Go app with nothing extra to run.

Frequently asked questions

Is go-wkhtmltopdf maintained?

The wrapper still works, but it execs the archived binary, and distros have been dropping that package, so fresh builds fail on the missing executable before the engine freeze even matters.

chromedp or Gotenberg for Go?

chromedp when rendering belongs inside the Go binary with nothing extra to run; Gotenberg when one container should serve every language and you accept operating it.

Method

Checked 2026-09-11 against the go-wkhtmltopdf README and the current chromedp and cdproto print documentation.


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

Going deeper: the Gotenberg vs Puppeteer head-to-head maps when the container is the right shape, the open-source comparison prices the container against hosted rates, and the webcapture product page is the hosted version of the same switch.

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.