Gotenberg is a well-maintained open-source Docker image (MIT license, regular v8 releases) that wraps Chromium and LibreOffice behind a multipart HTTP API. If you already run containers it is a great tool. This page is about the cases where operating it is more work than the PDFs are worth, and how to switch with minimal code changes.
# Before: Gotenberg (multipart form, margins in inches)
curl --request POST http://localhost:3000/forms/chromium/convert/url \
--form url=https://example.com \
--form paperWidth=8.27 --form paperHeight=11.7 \
--form marginTop=0.4 --form marginBottom=0.4 \
--form marginLeft=0.4 --form marginRight=0.4 \
--form printBackground=true \
-o out.pdf
# After: Shotmint (query string or JSON, named paper sizes)
curl -G https://shotmint.creasework.com/v1/pdf \
-H "X-API-Key: $SHOTMINT_KEY" \
--data-urlencode "url=https://example.com" \
-d format=A4 -d margin=10mm \
-o out.pdf
Gotenberg wants an index.html file part on /forms/chromium/convert/html. Here you POST the HTML string as JSON.
const html = "<h1>Invoice #42</h1><p>Total: 99.00 EUR</p>";
const r = await fetch("https://shotmint.creasework.com/v1/pdf", {
method: "POST",
headers: { "X-API-Key": process.env.SHOTMINT_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ html, format: "A4", margin: "15mm" }),
});
if (!r.ok) throw new Error(await r.text());
require("fs").writeFileSync("invoice.pdf", Buffer.from(await r.arrayBuffer()));
import os, requests
r = requests.get("https://shotmint.creasework.com/v1/screenshot",
headers={"X-API-Key": os.environ["SHOTMINT_KEY"]},
params={"url": "https://example.com", "width": 1280, "full_page": "true", "format": "webp"},
timeout=60)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
| Gotenberg form field | Shotmint |
|---|---|
url / index.html file | url / html (JSON body, up to 2 MB) |
paperWidth + paperHeight | format=A4 (A3, A5, Letter, Legal, Tabloid); custom sizes via CSS @page { size: … } |
marginTop/Bottom/Left/Right | margin=10mm (one value for all sides; use CSS @page margins for uneven ones) |
landscape, scale, printBackground | landscape, scale, print_background (on by default) |
emulatedMediaType=screen | screen_media=true |
waitDelay=1s | delay=1000 (ms), or wait_until=networkidle |
userAgent | user_agent |
emulatedMediaFeatures (prefers-color-scheme) | dark_mode=true |
Screenshot route: width, height, format, quality, omitBackground | width, height, format, quality, omit_background, plus full_page and selector |
header.html / footer.html, nativePageRanges, waitForExpression, cookies, LibreOffice and merge routes | Not supported. Repeat headers with a <thead> or fixed elements in your HTML |
10mm, 0.5in, 20px).index.html. Here, inline them (data URIs, a <style> block) or reference public https URLs.error field and is not charged; check r.ok before writing the file.Try the output first, no key needed: HTML to PDF and URL to PDF. Related: HTML invoices to PDF, wkhtmltopdf alternative, Puppeteer alternative.
One PDF or screenshot = one credit. €5 buys 2,000 renders, credits never expire and there's no subscription, so it beats an always-on container below a few thousand documents a month. Failed renders are refunded automatically.
No signup, no card. Get a key in one click, then buy credits only if you need more (from €5 for 2,000, never expire).
Get a free API key Full API reference