Blog

gPdf vs DocRaptor: edge rendering neden HTML-to-PDF'i yener

DocRaptor, HTML'i PDF'e çevirmek için hosted backend'de Prince kullanır. gPdf structured JSON'u doğrudan Cloudflare edge'de render eder. Fiyat farkı 18× ve bu teaser değildir.

DocRaptor yetkin bir üründür. HTML-to-PDF’in gold-standard engine’i olan Prince’i hosted REST API içine sarar; retries, async jobs ve iyi docs sağlar. On yılı aşkın süredir var ve birçok team için “Prince’i kendim çalıştırmak istemiyorum” durumunda obvious choice’tur.

Biz farklı bir tool shape’iyiz. gPdf hiç HTML almaz; structured JSON alır ve Cloudflare edge’de doğrudan PDF render eder. 100K pages/month list-price gap: $5/mo (gPdf Basic) vs $89/mo (DocRaptor Basic), yaklaşık 18×. Bu opening promo değildir. Structural’dır. Bu post neden bu structure’ın o price’ı ürettiğini ve her tool’un gerçekte nereye fit ettiğini açıklar.

İki mimari yan yana

LayerDocRaptor (HTML → PDF)gPdf (JSON → PDF)
InputHTML + CSS, Prince extensions for paged media ileJSON DocumentRequest
RendererPrince, compiled C++ engineCustom Rust engine, WebAssembly’a compiled
HostingDocRaptor centralised servers, US datacentre regionCloudflare Workers, her CF colo, 300+ cities
Cold startServer-side worker poolV8 isolate boot, single-digit ms
Per-render computeHTML/CSS üzerinde layout pass, sonra Prince paginationDirect typesetting, layout interpretation pass yok
Per-render p50~250-800 ms wall-clock, network + render~3-8 ms, network + render
Output determinismHigh, Prince matureByte-identical, same JSON → same bytes

Bu iki column’u “general HTML printer” ve “purpose-built document renderer” diye okursanız architectural decision’ı anlamış olursunuz. Geri kalan her şey, latency, cost ve feature lists dahil, o choice’ın downstream sonucudur.

Prince vergisi

Prince iyidir. Ayrıca çoğu invoice/receipt/label workflow’unun ihtiyaç duymadığı işi yapar: user’ın gönderebileceği arbitrary HTML için CSS Paged Media implement etmek; page-break rules, running headers, footnotes, cross-references, generated content boxes.

Bu generality’nin runtime cost’u vardır. Arbitrary HTML document’ı paginate etmek için engine şunları yapmak zorunda:

  1. HTML’i parse ve validate etmek
  2. CSS cascade’i parse ve resolve etmek, muhtemelen Prince’in kendi extensions’larıyla
  3. Render tree build etmek
  4. Multi-pass layout çalıştırmak, özellikle pages across tables veya balanced columns için
  5. Pages arasında cross-references resolve etmek
  6. PDF objects emit etmek

Bu passes’ın çoğu HTML’i input olarak kabul etmenin maliyetidir. Input zaten structured data ise, ki genelde öyledir çünkü invoice HTML’e wrap edilmeden önce bir yerde JSON object olarak vardır, her render’da compute ve latency olarak bu passes’ın bedelini ödersiniz ve output’a value eklemezler.

gPdf layout-interpretation step’ini tamamen atlar. JSON DocumentRequest page layout’u zaten structurally specify eder: { pages: [{ size, elements: [...] }] }. Renderer elements typeset eder, tables/lists’i deterministic şekilde paginate eder ve PDF emit eder. Resolve edilecek CSS cascade yok, compute edilecek float layout yok, cross-reference resolution pass yok.

Sonuç: DocRaptor’da ~300 ms süren aynı single-page invoice gPdf’te ~3 ms sürer. Daha hızlıyız çünkü daha hızlı Prince yazdık değil; daha hızlıyız çünkü Prince’in yaptığı şeylerin çoğunu yapmıyoruz.

”Gerçek olamayacak kadar ucuz” gerçek bir procurement itirazıdır

Bunu doğrudan ele almak gerekir, çünkü her B2B sales call’da karşımıza çıkar.

“$5/mo for 100K renders. DocRaptor $89. Anvil $0.10/PDF, yani aynı volume için $10,000. Sizinle ilgili sorun ne?”

Bunu charge edebilmemizin üç dürüst nedeni var:

1. Browser çalıştırmıyoruz

DocRaptor Prince infrastructure’ını customers arasında amortise eder. gPdf ise bir Cloudflare Worker’ı amortise eder; Workers Bundled’da maliyeti yaklaşık $0.50/million requests. JSON-shaped input ile renderer’ımız yaklaşık 1.5 ms CPU per render alır. Üzerine %50 margin koysanız bile cents-per-thousand-renders range’inde kalırsınız. Aritmetik fiyatın kendisidir.

2. Control plane çalıştırmıyoruz

Async jobs yok, callbacks yok, retry queue yok, document storage yok, preview-link UI yok, multi-tenant database yok. Her render stateless function’a tek round-trip ve dönüşten ibarettir. Bu, çoğu “PDF API” şirketinin bütçelediği tüm ops surface’i kaldırır; aynı surface onların price’ını justify eder.

3. Model zarar edeceğimiz workloads’u kendisi dışarı iter

Document gerçekten HTML-to-PDF istiyorsa, örneğin 60-page legal contract veya complex CSS-Grid report, ilk hour içinde JSON model’dan bounce eder ve DocRaptor’a gidersiniz. Bu workloads için defensive pricing yapmamız gerekmez, çünkü self-route ederler. Yalnızca “structured-data-to-document” workloads’un long-but-narrow tail’i için price etmemiz gerekir; burada per-render cost gerçekten tiny’dir.

Toplamda: $5/100K loss leader değildir; actual cost-of-goods-sold plus margin’dir. Browser ship etmediğinizde underlying compute gerçekten bu kadar ucuz olduğu için bunu sürdürebiliriz.

DocRaptor nerede doğru seçimdir

Self-serving comparison yazmamaya çalışıyoruz. DocRaptor’ın gerçekten kazandığı cases:

  • Input tamamen control etmediğiniz HTML ise. User-generated reports, third-party templates, CMS’ten Markdown-to-HTML output. Arbitrary input için JSON mapper yazmak istemezsiniz.
  • Prince’in support ettiği CSS Paged Media features’a ihtiyacınız varsa. Running headers/footers per chapter, complex footnote reflow, named-page selectors, generated tables of contents, indexes. gPdf common subset için structured equivalents sunar, ama @page :left selectors içinde yaşıyorsanız Prince sizin dostunuzdur.
  • Content team’iniz HTML/CSS yazar, JSON değil. Non-engineering team’e JSON authoring workflow dayatmayın. Bundan nefret ederler.
  • Async + callbacks + document storage as a service. DocRaptor generated PDFs’i store eder ve delivery için signed URLs verir. gPdf strictly stateless’tir; sonucu sizin code’unuz store eder.

Bu buckets’tan birindeyseniz, DocRaptor’da kalın. Doğru tool odur.

gPdf nerede doğru seçimdir

Ters görüntü:

  • Inputs zaten structured data: database rows, JSON API payloads, queue messages.
  • Latency önemlidir: interactive checkout flows, real-time label printing, on-demand statement generation.
  • Tests, audit trails veya e-invoice retention için byte-identical reproducibility önemlidir.
  • Birkaç thousand renders/month üstündeki her volume’da cost-sensitive’sinizdir.
  • GS1-128, QR, Data Matrix, PDF417, Aztec, MaxiCode gibi barcodes’u sub-millimetre precision ile üretmeniz gerekir. Prince technically SVG barcodes support eder, ama HTML/CSS üzerinden 0.1 mm overall length precision non-trivial’dır.
  • Compliance için PDF/A (1b/2b/3b/4) veya Factur-X / ZUGFeRD attachments gerekir.
  • JSON-to-PDF pipeline çalıştırabilecekken JSON-to-HTML-to-PDF pipeline çalıştırmak istemezsiniz.

Migration mekaniktir, stratejik değil

Yaygın endişe: “Switch etmek tüm templates’i rewrite etmek demek.” Genelde değil. Çoğu HTML-to-PDF template %20 layout’tur, bu bir kez JSON structure olur, ve %80 data interpolation’dır, renderer ne alırsa alsın aynıdır.

Practical path:

  1. Migrate etmek için tek document type seçin. Highest-volume olanla başlayın; biggest savings, smallest blast radius.
  2. HTML template’in data interface’ini, yani interpolate ettiği variables’ı alın ve küçük bir mapToDocumentRequest(data) function yazın.
  3. Output match edene kadar Playground’da iterate edin.
  4. Production’da A/B yapın: traffic’in %5’ini iki hafta gPdf’e route edin. PDFs diff edin. Bills compare edin.
  5. Vibes’a değil data’ya göre roll forward veya roll back yapın.

Teams’in bunu tek sprint’te yapıp sonraki ay PDF bill’inin %90’ını cebine koyduğunu gördük. Workload’unun gerçekten HTML-to-PDF case olduğunu fark edip DocRaptor’da kalan teams de gördük; bu da doğru decision’dı.

TL;DR

DocRaptorgPdf
Best atArbitrary content için HTML → PDFStructured documents için JSON → PDF
Price (100K pages/mo)$89$5
p50 render250-800 ms3-8 ms
Edge-deployedHayır, centralisedEvet, 300+ Cloudflare colos
Async + storageEvet, includedHayır, stateless by design
PDF/A + Factur-XPrince extensions üzerindenbuilt-in

Documents’ınız renderer için HTML giydirilmiş structured data ise, var olması gerekmeyen translation step için ödeme yapıyorsunuz. Playground’ı deneyin: invoices’larınızdan birini JSON ile describe edin, browser’da 5 ms altında render edin ve gap’in gut feeling’inizle uyuşup uyuşmadığını görün.