An HTML-to-PDF API built on a commercial rendering engine, producing print-quality documents with headers, footers, page numbers and real pagination.
Build me an HTML-to-PDF service that replaces DocRaptor: real pagination, running headers, page numbers, and documents that look right when printed. STACK - Node 20+ with Fastify for the API - SQLite through better-sqlite3 for jobs and history - Two rendering engines behind one interface: WeasyPrint for correct paged CSS, and headless Chromium for documents that need JavaScript. Choose per job - Caddy in front THE DATA MODEL - documents: id, uid, name, engine, template_id, payload_hash, status, page_count, bytes, ms, output_path, error, created_at - templates: id, uid, name, html, css, assets_json, version, created_at - template_versions: id, template_id, version, html, css, created_at — a rendered document records the version it used - api_keys: id, name, hash, rate_per_minute, max_bytes, created_at, revoked_at - fonts: id, family, weight, style, file_path - Renders are cached by a hash of template version and payload: the same invoice asked for twice returns the same bytes PAGED CSS, WHICH IS THE ENTIRE DIFFICULTY - @page with size, margins, and named pages for a different first page - Running headers and footers through @top-center, @bottom-right and their siblings, filled from running elements - Page numbers with counter(page) and counter(pages), and 'page 3 of 11' working on the first pass - Page breaks: break-before, break-after, break-inside: avoid, and orphans and widows set to at least two. A heading alone at the foot of a page is the defect everyone notices - Table headers repeating on every page with thead, and a caption that does not repeat - Footnotes at the foot of their own page where the engine supports it, and documented as unsupported where it does not - A table of contents built from target-counter, so the page numbers in it are real - Say plainly which of these the browser engine cannot do. Chromium has no running elements and no footnotes; that is exactly why the paged engine is the default here THE API - POST html or a template uid with a payload, get a document - Synchronous under a deadline, asynchronous with a webhook above it, chosen by the caller - Idempotency keys, so a retry never renders twice - Errors that name the cause: a missing font, an unfetchable image, a stylesheet that failed to parse, a document that exceeded the page limit - A test mode that renders with a watermark and does not count against limits ASSETS, WHERE DOCUMENTS BREAK IN PRODUCTION - Every font is uploaded and stored locally. A document that fetches a font at render time is a document that renders differently at three in the morning - Images fetched once, hashed and cached, with a timeout, a size cap, and no redirects to private addresses. This is a server following URLs a client supplied — treat every fetch as hostile - Base64 data URIs accepted, so a caller can avoid the fetch entirely - A missing asset either fails the render or renders a placeholder, declared per request, never silently omitted PRINT CONCERNS - Page size and orientation per document, including the ones outside A4 and Letter - Bleed and crop marks for anything going to a printer - PDF/A output for archiving, with the colour profile embedded - Metadata: title, author, subject, keywords, and the creation date set deterministically so two renders of the same input match byte for byte - Optional encryption with an owner password and permissions - Merging several documents, and appending a cover SANDBOXING - Rendering runs in a container with no network except an allow-listed proxy for asset fetches, a memory cap, a CPU quota and a wall-clock timeout - Non-root, read-only root filesystem, tmpfs for work - The renderer processes untrusted HTML from API callers. Treat it as remote code execution waiting to happen and say so in the README THE INTERFACE - A page to paste HTML and CSS, render, and see the result with page boundaries drawn - A template editor with a preview that paginates live - Document history with the payload and the log for the operator OPERATIONS - .env: DATABASE_PATH, STORAGE_PATH, BASE_URL, SIGNING_SECRET, MAX_PAGES, CONTAINER_RUNTIME - Migrations on boot, each once - A render queue with a concurrency cap; rendering is CPU-bound - Disk watchdog, and expiring output files - Health endpoint that renders a one-page document through the real path WHAT MATTERS MOST Pagination. Build a test document that is forty pages of tables with a repeating header, a table of contents and 'page N of M', and get it right before anything else exists. Everything in this product that is hard is on the second page. Give me the repository, the container definition, migrations, .env.example, an invoice template as a seed, and a README with deploy steps behind Caddy and a table of what each engine supports.
What you lose
- A commercial print engine that handles page breaks, running headers and footnotes correctly
- Rendering capacity you do not provision
- Support when a document paginates wrongly, which it eventually will
If you would rather not build
- Typst or LaTeX, for documents that are genuinely typeset
What it costs
as published on their pricing page
| Plan | Billed monthly | Billed yearly | Last read |
|---|---|---|---|
| — | $15/mo | — | — |
Their pricing page is where these came from. Seeing a different price? Tell us.
The escape hatch
open source · no votes, no paid placement
WeasyPrint
$0Renders HTML and CSS to PDF with proper pagination, no browser.
Kozea/WeasyPrintfree · open source
Why this verdict
our own opinion · changed only by a person
84/100
Verdict yes at 84. Playwright prints well enough for invoices and reports; the print stylesheet is where the effort goes.
History
tracked since 10 Aug 2026 · nothing is ever overwritten
Questions about DocRaptor
answered from the record above
Is DocRaptor free?
No — the plan we track is $15 a month. From around $15/month billed monthly for a fixed number of documents.
Can you replace DocRaptor by building your own?
YES. Replaceable in one session with an AI coding agent. Replacement score 84 out of 100, build time one session. Read what you lose before you decide.
How much does DocRaptor cost?
$15 a month on Basic — $180 a year. Recorded 10 Aug 2026.
What do you lose by replacing DocRaptor?
A commercial print engine that handles page breaks, running headers and footnotes correctly; Rendering capacity you do not provision; Support when a document paginates wrongly, which it eventually will. If any of those carry weight for you, keep paying.
Is there an open-source alternative to DocRaptor?
Yes: WeasyPrint, Playwright. The prompt on this page is for when you want it your way instead.
Related entries
same category first, most replaced first
Every week, something stops being worth paying for.
New verdicts, prices that moved, entries added. One email a week. Unsubscribe in one click. Nothing is being sent yet — your address is kept here, and the first issue is the first thing it is used for.
free forever · no tracking pixel · stored here, never passed to anyone

