Blog

gPdf vs DocRaptor: waarom edge-rendering HTML-naar-PDF verslaat

DocRaptor gebruikt Prince om HTML naar PDF om te zetten op een gehoste backend. gPdf rendert gestructureerde JSON direct op de Cloudflare-edge. Het prijsverschil is 18×. Hier waarom dat geen lokmiddel is.

DocRaptor is een competent product. Het wikkelt Prince — de gouden standaard HTML-naar-PDF-engine — in een gehoste REST API, met retries, async jobs en behoorlijke documentatie. Het bestaat al meer dan tien jaar en voor veel teams is het de voor de hand liggende «ik wil Prince niet zelf draaien»-keuze.

Wij zijn een tool van een andere vorm. gPdf accepteert helemaal geen HTML; het neemt gestructureerde JSON en rendert direct op de Cloudflare-edge. Het lijst-prijsverschil bij 100K pagina’s/maand: $5/maand (gPdf Basic) vs $89/maand (DocRaptor Basic) — ongeveer 18×. Dat verschil is geen openingspromotie. Het is structureel. Deze post legt uit waarom de structuur die prijs produceert en waar elke tool eigenlijk past.

De twee architecturen, naast elkaar

LaagDocRaptor (HTML → PDF)gPdf (JSON → PDF)
InvoerHTML + CSS (met Prince paged-media-extensies)JSON DocumentRequest
RendererPrince (gecompileerde C++-engine)Eigen Rust-engine, gecompileerd naar WebAssembly
HostingGecentraliseerde DocRaptor-servers (US datacenter)Cloudflare Workers, elke CF-colo (300+ steden)
Cold startServer-side worker poolV8-isolate boot, eencijferige ms
Compute per renderLayout-pass over HTML/CSS, daarna Prince pagineertDirecte compositie, geen layout-interpretatiepass
p50 per render~250–800 ms wall-clock (netwerk + render)~3–8 ms (netwerk + render)
Output-determinismeHoog (Prince is volwassen)Byte-identiek (zelfde JSON → zelfde bytes)

Als je deze twee kolommen leest als «algemene HTML-printer» vs «doelgebouwde document-renderer», heb je de architecturale beslissing al begrepen. Al het andere (latentie, kosten, zelfs de feature-lijsten) is stroomafwaarts van die ene keuze.

De Prince-belasting

Prince is goed. Het doet ook werk dat de meeste invoice/bon/label-workflows niet nodig hebben: CSS Paged Media implementeren — pagina-breakregels, doorlopende headers, voetnoten, kruisreferenties, gegenereerde inhoud — voor willekeurige HTML die de gebruiker erin zou kunnen gooien.

Die algemeenheid heeft runtime-kosten. Om willekeurige HTML te pagineren, moet de engine:

  1. HTML parsen en valideren
  2. CSS-cascade resolven (mogelijk met Prince’s eigen extensies)
  3. Render-tree bouwen
  4. Multi-pass layout draaien (vooral voor tabellen die over pagina’s lopen, of kolommen die balanceren)
  5. Kruisreferenties tussen pagina’s resolven
  6. PDF-objecten emitteren

Het meeste van die passes zijn de kosten van HTML accepteren als invoer. Als je invoer al gestructureerde data is (wat het bijna altijd is — je factuur bestaat als JSON-object voordat je het in HTML wikkelt), betaal je voor die passes in compute en latentie bij elke render, en ze voegen geen waarde toe aan de output.

gPdf slaat de layout-interpretatiestap volledig over. De JSON DocumentRequest specificeert al de page layout structureel — { pages: [{ size, elements: [...] }] }. De renderer typeert de elementen, pagineert tabellen/lijsten deterministisch en emit PDF. Geen CSS-cascade om te resolven, geen float-layout om te berekenen, geen pass voor kruisreferentie-resolution.

Het resultaat: dezelfde één-paginafactuur die ~300 ms duurt op DocRaptor duurt ~3 ms op gPdf. We zijn niet sneller omdat we een snellere Prince hebben geschreven — we zijn sneller omdat we niet doen wat Prince meestal doet.

«Te goedkoop om waar te zijn» is een echt procurement-bezwaar

Laten we het direct adresseren want het komt in elk B2B-salesgesprek naar voren.

«$5/maand voor 100K renders. DocRaptor is $89. Anvil is $0,10/PDF (dus $10.000 bij hetzelfde volume). Wat is er mis met jullie?»

Drie eerlijke redenen waarom we dit kunnen rekenen:

1. We draaien geen browser

DocRaptor verdeelt Prince-infrastructuur over klanten. gPdf verdeelt één Cloudflare Worker, die ongeveer $0,50/miljoen requests kost op Workers Bundled. Met JSON-vormige invoer neemt onze renderer ongeveer 1,5 ms CPU per render. Stapel 50 % marge en je zit nog steeds in het centen-per-duizend-renders-bereik. De rekenkunde is de prijs.

2. We draaien geen control plane

Geen async jobs, geen callbacks, geen retry-queue, geen documentopslag, geen preview-link UI, geen multi-tenant database. Elke render is een enkele round-trip naar een stateless functie en terug. Dat verwijdert de hele ops-oppervlakte die de meeste «PDF API»-bedrijven begroten — wat ook de oppervlakte is die hun prijs rechtvaardigt.

3. Het model selecteert zichzelf uit de workloads waarop we geld zouden verliezen

Als je document echt HTML-naar-PDF nodig heeft (60-pagina juridisch contract, complex CSS-Grid-rapport), bots je in het eerste uur weg van het JSON-model en ga je toch naar DocRaptor. We hoeven defensief geen prijs te zetten voor die workloads omdat ze zichzelf routeren. We hoeven alleen prijs te zetten voor de lange-maar-smalle staart van «gestructureerde-data-naar-document»-workloads, waar de kosten per render echt minuscuul zijn.

Samen: $5/100K is geen loss-leader, het is de werkelijke kostprijs plus marge. We kunnen het oneindig daar houden omdat de onderliggende compute echt zo goedkoop is wanneer je geen browser meelevert.

Waar DocRaptor de juiste keuze is

We proberen geen eigen-belang vergelijkingen te schrijven. De gevallen waar DocRaptor echt wint:

  • Je invoer is HTML die je niet volledig controleert. Door gebruikers gegenereerde rapporten, third-party templates, Markdown-uit-CMS-gerenderd-naar-HTML. Je wilt geen JSON-mapper schrijven voor willekeurige invoer.
  • Je hebt CSS Paged Media-features nodig die Prince ondersteunt. Doorlopende headers/footers per hoofdstuk, complexe voetnoot-reflow, named page-selectors, gegenereerde inhoudsopgaven, indexen. gPdf heeft gestructureerde equivalenten voor de gemeenschappelijke subset, maar als je in @page :left-selectors leeft, is Prince je vriend.
  • Je hebt een content-team dat HTML/CSS schrijft, geen JSON. Leg geen JSON-authoring-workflow op aan een non-engineering team. Ze zullen je haten.
  • Async + callbacks + documentopslag als service. DocRaptor slaat gegenereerde PDFs op en geeft je signed URLs voor levering. gPdf is strikt stateless — jouw code slaat het resultaat op.

Als je in een van deze emmers zit, blijf bij DocRaptor. Het is de juiste tool.

Waar gPdf de juiste keuze is

Het spiegelbeeld:

  • Je invoer is al gestructureerde data (database-rijen, JSON API-payloads, queue-berichten).
  • Latentie is belangrijk — interactieve checkout-flows, real-time labelprinten, on-demand statement-generatie.
  • Je geeft om byte-identieke reproduceerbaarheid voor tests / audit trails / e-factuur-bewaring.
  • Je bent kostengevoelig bij elk volume boven enkele duizenden renders/maand.
  • Je hebt barcodes (GS1-128, QR, Data Matrix, PDF417, Aztec, MaxiCode) nodig met sub-millimeter precisie.
  • Je hebt PDF/A (1b/2b/3b/4) of Factur-X / ZUGFeRD-bijlagen nodig voor compliance — vooral relevant voor de Nederlandse Peppol BIS 3 verplichting vanaf 2026 en de Duitse / Franse mandaten al van kracht.
  • Je zou liever geen JSON-naar-HTML-naar-PDF-pipeline draaien als je een JSON-naar-PDF-pipeline kunt draaien.

Specifieke noot voor Nederlandse teams over Peppol BIS 3

Als je context het Nederlandse e-factuur-mandaat is — Peppol BIS 3 wordt vereist voor B2G overheidsfacturatie en uitgebreid naar B2B vanaf 2026 — produceert gPdf het verwachte Factur-X / UBL-formaat in een enkele API-call:

curl -X POST https://gpdf.com/api/v1/e-invoice/render \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "document": { "pages": [{ "size": "a4", "elements": [...] }] },
    "einvoice": {
      "format": "factur-x",
      "profile": "BASIC",
      "xml": "<rsm:CrossIndustryInvoice>...</rsm:CrossIndustryInvoice>"
    }
  }' \
  --output factuur.pdf

Geen Ghostscript-postpass, geen tweede tool om de XML aan te hechten, geen validatie-loterij tussen stappen. De output-bytes zijn byte-identiek tussen engine-versies, dus je bewarings-hash voor de 7-jarige fiscale verplichting kan stabiel blijven.

Migratie is mechanisch, niet strategisch

Een veelvoorkomende zorg: «Wisselen betekent al onze templates herschrijven». Meestal niet. De meeste HTML-naar-PDF templates zijn 20 % layout (wat één keer JSON-structuur wordt) en 80 % data-interpolatie (wat exact hetzelfde is ongeacht wat de renderer accepteert).

Praktisch pad:

  1. Kies één documenttype om te migreren. Begin met de hoogste volume — grootste besparingen, kleinste blast radius.
  2. Neem de data-interface van het HTML-template (de variabelen die het interpoleert) en schrijf een kleine mapToDocumentRequest(data) functie.
  3. Itereer tegen de Playground tot de output matcht.
  4. A/B in productie: route 5 % van het verkeer naar gPdf gedurende twee weken. Diff de PDFs. Vergelijk facturen.
  5. Roll forward of terug op basis van data, niet vibes.

TL;DR

DocRaptorgPdf
Best voorHTML → PDF voor willekeurige contentJSON → PDF voor gestructureerde documenten
Prijs (100K pagina’s/maand)$89$5
Render p50250–800 ms3–8 ms
Edge-deployed❌ gecentraliseerd✅ 300+ Cloudflare colos
Async + storage✅ inbegrepen❌ stateless by design
PDF/A + Factur-X / ZUGFeRD⚠️ via Prince-extensies✅ ingebouwd

Als je documenten gestructureerde data zijn vermomd als HTML voor een renderer, betaal je voor een vertaalstap die niet hoeft te bestaan. Probeer de Playground — beschrijf een van je facturen in JSON, render het in je browser in minder dan 5 ms, kijk of de kloof overeenkomt met je intuïtie.