🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)
🕵️ SicherheitslückenHak5: Hackers Just Poisoned the Rust Supply Chain | Threat Wire(01.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenHak5: Hackers Found a Way Into Humanoid Robots | Threat Wire(04.09.2026 um 15:04 Uhr)
🔧 AI Nachrichten Bits und so #1021 (Passwort für Laufwerk)(31.08.2026 um 22:15 Uhr)
🔧 AI Nachrichten Bits und so #1022 (Wie Weißbier)(06.09.2026 um 20:39 Uhr)
🍏 iOS / Mac OSHue-App 6.0 ist da: das sind die Neuerungen(07.09.2026 um 17:21 Uhr)

🔧 Programmierung 🕛 kürzlich 4 Min Lesezeit
0

Render PDF invoices from an HTML template without putting Chromium in your backend

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

You already have an invoice template. It is HTML and CSS, it renders correctly in a browser, and the accountant wants a PDF. So you install Puppeteer, and now your container carries a Chromium build, your serverless bundle blows past the size limit, and you own a font package and a pile of shared libraries you never asked for.



The rendering is not the hard part. Owning the browser is. SnapPDF takes a public URL and hands back PDF bytes, so the browser lives on someone else's box.






One GET, raw bytes back



The whole API surface is a single endpoint:




CODE
GET /v1/pdf?url=https://EXAMPLE.com






Point it at the URL where your invoice already renders:




CODE
curl -o inv-2043.pdf \
--get "https://snappdf.dedyn.io/v1/pdf" \
--data-urlencode "url=https://example.com/invoices/inv-2043" \
--data-urlencode "format=A4" \
--data-urlencode "background=true" \
--data-urlencode "wait_for_selector=#invoice-total"






Use --get with --data-urlencode rather than pasting a query string. Your invoice URL probably carries a signed token, and an unescaped & will silently truncate it.



The optional params: format (A4 by default; A3, A5, Letter, Legal, and Tabloid also work), landscape, background, scale, and wait_for_selector.






From Node, with global fetch



No SDK. Build the URL, read the body as an ArrayBuffer.




CODE
import { writeFile } from 'node:fs/promises';

async function renderInvoicePdf(invoiceUrl) {
const endpoint = new URL('https://snappdf.dedyn.io/v1/pdf');
endpoint.searchParams.set('url', invoiceUrl);
endpoint.searchParams.set('format', 'A4');
endpoint.searchParams.set('background', 'true');
endpoint.searchParams.set('wait_for_selector', '#invoice-total');

const res = await fetch(endpoint);

// Success is application/pdf. Failure is a JSON body with an `error` field.
if (!res.ok) throw new Error(`snappdf ${res.status}: ${await res.text()}`);

return Buffer.from(await res.arrayBuffer());
}

const pdf = await renderInvoicePdf('https://example.com/invoices/inv-2043');
await writeFile('inv-2043.pdf', pdf);

console.log(pdf.subarray(0, 5).toString()); // %PDF-






Two things trip people up here. The response is not JSON, so res.json() throws on the happy path. And a 200 with a body that does not start with %PDF- means you rendered someone's login wall, not your invoice.






What the response actually is



Content-Type: application/pdf, and the body is the file. Nothing to unwrap, no base64, no job ID to poll. You can stream it straight to S3, pipe it into a res.send(), or attach it to an email without touching disk.



background=true matters more than it sounds. Chromium drops background colors when printing by default, which turns the colored header row on your line-item table into white on white. Turn it on and your CSS survives.






The thing worth building



Wire it into invoice generation instead of calling it by hand.



When an invoice moves to finalized, mint a short-lived signed URL for the HTML view you already render for the customer, pass that URL to SnapPDF, and write the returned bytes to object storage keyed by invoice ID. The PDF is now a cached artifact, not a render you repeat on every download click. Your template stays one HTML file that designers can edit, and the PDF follows it.



The important detail: your invoice route has to be reachable from the public internet. SnapPDF refuses loopback, private, and link-local addresses, so http://localhost:3000/invoices/1 returns an error rather than a PDF. In development, run a tunnel. In production, a signed URL that expires in sixty seconds is enough.






Rough edges I hit



wait_for_selector is best effort. If the selector never appears, you still get a PDF of whatever managed to load, which is the right behavior for a rendering service and the wrong behavior if you assumed it would fail loudly. Check for your total in the output before you email it to a customer.



scale is clamped to Chromium's own 0.1 to 2.0 range. Values outside that get pulled back in rather than rejected.



Long-polling or websocket-heavy pages take longer than static ones, because the renderer waits for the network to settle before printing. Invoices are static. Dashboards are not.



Working curl and Node examples live at github.com/clause-netizen/snappdf-api if you want to copy something that runs.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
Hackers Just Poisoned the Rust Supply Chain | Threat Wire
1 Quelle
Hackers Found a Way Into Humanoid Robots | Threat Wire
1 Quelle
Bits und so #1021 (Passwort für Laufwerk)
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Render PDF invoices from an HTML template without putting Chromium in your backend

Thematisch verwandte Begriffe: Render, invoices, from, HTML · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...