Short answer
An HTML to PDF API is a web service that accepts HTML markup or a URL in an HTTP request, renders it in a browser engine such as headless Chromium, and returns the result as a PDF file. It lets any backend produce print-quality documents without installing or operating a browser or PDF library itself.
Sooner or later a product has to hand someone a file they can print, sign or archive. For a web team the content already exists as HTML, so printing that HTML to PDF looks like an afternoon of work. Then page two arrives: a table row sliced through the middle, a web font that quietly turned into a generic sans-serif, a footer too small to read.
An HTML to PDF API takes that conversion off your servers. You send markup or a URL over HTTP and get PDF bytes back. Below we cover how a request moves through one, the options you will set most, how the approach stacks up against libraries and self-hosted Chromium, and the cases where you should skip it. Our examples call htmltopdfapi.co, the HTML to PDF API we run on headless Chromium, but the ideas carry over to any vendor.
What is an HTML to PDF API?
An HTML to PDF API is a REST endpoint that takes a document description as input and returns PDF bytes as output. The input is either a string of HTML (often rendered from a template such as Blade, Jinja, ERB or JSX) or a public URL the service should open. The output is a binary PDF, usually with the application/pdf content type, which your code can stream to a user, attach to an email or store in object storage.
What matters most is the rendering engine. Current APIs drive a real browser, almost always headless Chromium, so the PDF follows the same CSS Chrome does, including flexbox, grid, web fonts, SVG, @page rules and page-break properties. Older tools re-implemented a subset of CSS themselves. That is why an invoice laid out with display: flex looks right in the browser and comes out of DomPDF as one stacked column.
How does an HTML to PDF API work?
Each request passes through five stages. When you debug a blank page, a missing image or a timeout, most of the work is figuring out which stage it failed in.
- Request. Your server sends an authenticated HTTP
POSTwith a JSON body containinghtmlorurlplus rendering options such as paper size and margins. - Validation. The service checks the API key and the parameters. Bad input returns a JSON error (for example a 422 with a field-by-field
errorsobject) instead of a PDF. - Render. A headless Chromium instance loads the HTML, fetches referenced assets such as images, stylesheets and fonts, runs JavaScript, and waits for the page to be ready according to the wait strategy you chose.
- Print. Chromium runs its print-to-PDF routine with your paper size, orientation, margins and header/footer templates, splitting content into pages.
- Response. The PDF bytes come back in the HTTP response body. Nothing needs to be polled or downloaded from a second URL.
curl -X POST https://platform.htmltopdfapi.co/api/v1/pdf/generate \
-H "Authorization: Bearer $HTML_TO_PDF_API_KEY" \
-H "Content-Type: application/json" \
-d '{"html": "<h1>Hello, PDF</h1><p>Rendered by headless Chromium.</p>", "paper_size": "a4"}' \
--output hello.pdfOne HTTP call, one file on disk. On htmltopdfapi.co, Chromium runs inside AWS Lambda, so no browser process ever starts on your own machines. The getting started guide covers API keys and error handling.
What can you send: HTML or a URL?
Each request carries one of two inputs.
An HTML string. You render a template on your own server and send the markup. Use this for private data such as invoices or payroll reports, because the page never has to be publicly reachable. Assets need to be inlined (base64 data URIs, an inline <style> block) or hosted on public URLs. A relative <img src="/logo.png"> comes out as a broken image, since the renderer has no host to resolve that path against. On htmltopdfapi.co the html field accepts up to 50,000 characters.
A URL. You send an address and the service opens it the way a browser would. That suits public pages, documentation, or a dashboard behind a signed, short-lived link. Sending http://localhost:3000/invoice/7 fails: from the renderer's side, localhost is the renderer itself, and your private network is out of reach too.
Past the input, these are the parameters you will set most often.
| Parameter | What it does | Example |
|---|---|---|
html / url | The content to render. One of the two is required. | "url": "https://example.com/report" |
paper_size | Standard sheet size: a4, a3, a5, letter or legal. | "paper_size": "letter" |
paper_width / paper_height | Custom size in millimeters, used instead of paper_size. Both are required together. | "paper_width": 100, "paper_height": 150 |
orientation | Portrait or landscape. | "orientation": "landscape" |
margin_top … margin_left | Page margins in millimeters (0–250). | "margin_top": 20 |
header_html / footer_html | Chromium header and footer templates, repeated on every page. | "footer_html": "<div style=\"font-size:9px\">…</div>" |
show_header_footer | Turns the header/footer templates on. | "show_header_footer": true |
print_background | Includes background colors and images, which browsers drop when printing by default. | "print_background": true |
css_media_type | Renders with screen or print media rules. | "css_media_type": "print" |
wait_until | When the page counts as loaded: load, domcontentloaded, networkidle0 or networkidle2. | "wait_until": "networkidle0" |
wait_for_selector | Waits until a CSS selector exists, useful for charts rendered by JavaScript. | "wait_for_selector": "#chart-ready" |
delay / timeout | Extra wait in ms (0–30000) and the overall render limit in seconds (1–120). | "delay": 500, "timeout": 60 |
filename / download | Suggested file name and whether to send it as an attachment. | "filename": "invoice-42.pdf" |
How do HTML-to-PDF approaches compare?
An API is one of four broad ways to get from HTML to PDF. They differ mainly in how faithfully they render your CSS and how much infrastructure you end up running.
| Approach | Examples | Pros | Cons |
|---|---|---|---|
| Client-side JavaScript | jsPDF, html2pdf.js | Runs in the user's browser; no server cost; works offline. | Often rasterizes the page into an image (blurry text, no selectable text); output varies by device; cannot run in a background job. |
| Server-side PDF library | DomPDF, WeasyPrint, mPDF | Single package install; no external calls; predictable for simple layouts. | Own CSS engine with partial support (DomPDF has no flexbox or grid); JavaScript is not executed; complex layouts need rework. |
| Self-hosted headless browser | Puppeteer, Playwright, Browsershot | Full Chromium fidelity; complete control; data stays on your infrastructure. | You install and patch Chromium, size memory, handle crashes, zombie processes and concurrency, and deal with bundle limits on serverless. |
| Hosted HTML to PDF API | htmltopdfapi.co and others | Chromium fidelity with no browser to operate; one HTTP call from any language; scales with request volume. | Network dependency; documents leave your infrastructure; per-page cost at high volume; vendor lock-in on options. |
If you are deciding specifically between running Puppeteer yourself and calling an API, Puppeteer vs an HTML to PDF API goes deeper on the operational side. Teams migrating off older tools may also want the wkhtmltopdf alternative guide or the DomPDF alternative guide.
When should you not use an HTML to PDF API?
We would rather you skip an API than adopt one that does not fit. These are the cases where we point people elsewhere, our own service included.
- Offline or air-gapped systems. If the machine generating PDFs cannot reach the internet, a hosted API is off the table. Use a library or a self-hosted Chromium.
- Strict data residency or confidentiality rules. If policy says documents may not leave your network or a specific region, sending HTML to a third party may not be allowed regardless of the vendor's controls. Self-host the renderer.
- Tiny, simple volume. If you generate a few dozen plain receipts a month and DomPDF or WeasyPrint already renders them correctly, adding an external dependency buys you little.
- Client-only apps. A static site that lets a user save their own notes as a PDF can often use the browser's built-in print dialog or a client-side library without any server.
- Latency-sensitive paths. A network round trip plus a browser render takes seconds once fonts and images load. If a PDF has to appear inside a tight request budget, generate it in a queue and notify the user when it is ready.
What security and data handling questions should you ask a vendor?
The HTML you send carries customer names, addresses, amounts and contract terms. Get written answers to these questions from any provider before the first production request:
- Is the HTML or the generated PDF stored after the response is sent, and if so, for how long and where?
- Which region does rendering run in, and which subprocessors (cloud host, logging, error tracking) can see request data?
- Is traffic encrypted in transit, and how are API keys scoped, rotated and revoked?
- Can the renderer reach internal networks or cloud metadata endpoints when it loads a URL or an asset? (This is a server-side request forgery risk.)
- Are request bodies written to logs? A debug-level request logger left on in production leaks more data than most storage policies ever would.
- Is there a data processing agreement available if you are subject to GDPR or similar rules?
If an answer is vague, treat it as "no". For htmltopdfapi.co you can ask these directly through the contact page.
How much does an HTML to PDF API cost?
Vendors bill by usage, but the unit differs. Some count API calls, some count documents, some count rendered pages. Per-page billing tracks real cost most closely when document length varies, since a ten-page report also takes longer to render than a one-page receipt.
htmltopdfapi.co counts every rendered PDF page as one page. The Free plan is $0 with 200 pages per day, one API key and a 5 MB input limit, with no credit card required. Pro is $29 per month for 50,000 pages per month, five API keys, a 25 MB input limit and priority email support. Enterprise is custom-priced with unlimited pages and keys, a 100 MB input limit, dedicated support and an SLA. Current details are on the pricing page.
Price the self-hosted option properly when you compare. Chromium costs nothing to download, but you still pay for the memory each browser process holds, the time spent on version upgrades, and the on-call page when a render hangs and never returns.
What is an HTML to PDF API used for?
These are the documents we see rendered most, each with its own walkthrough.
- Invoices and receipts: render a billing template per order, store the PDF and email it.
- Reports: multi-page analytics or financial reports with tables that span pages and repeat their headers.
- Contracts: agreements generated from a template with consistent margins and page numbering, ready for signature.
- Certificates: landscape, single-page designs with web fonts and background artwork.
- Dashboard exports: snapshot a JavaScript chart dashboard by URL, waiting for charts to finish drawing.
Whatever the document, two layout questions come up within the first week. We answer them separately in adding page numbers, headers and footers and controlling page breaks with CSS.
How do you call an HTML to PDF API from your framework?
The interface is plain HTTP and JSON, so any language with an HTTP client can call it. PHP and Laravel get an official SDK (composer require htmltopdfapi/php-sdk); everything else uses its standard client. We keep a guide per stack:
- Laravel and Laravel invoice PDFs
- Plain PHP
- Node.js and Next.js
- Python and Django
- Ruby on Rails
- curl and shell scripts
- Serverless functions and a PDF microservice
- No-code: n8n and Zapier
use HtmlToPdfApi\Laravel\Facades\HtmlToPdf;
public function show(Invoice $invoice)
{
$html = view('invoices.pdf', compact('invoice'))->render();
return HtmlToPdf::html($html)
->paperSize('a4')
->margins(top: 20, bottom: 20)
->filename("invoice-{$invoice->id}.pdf")
->generate(); // PdfResponse is Responsable, so this streams the PDF
}If you are still choosing a provider, the comparison of HTML to PDF APIs lists the main options and what to check in each.
Frequently asked questions
What is an HTML to PDF API?
An HTML to PDF API is a web service that receives HTML or a URL over HTTP, renders it in a browser engine such as headless Chromium, and returns a PDF file in the response.
Does an HTML to PDF API support modern CSS like flexbox and grid?
APIs built on headless Chromium support the same CSS as Chrome, including flexbox, grid, web fonts and page-break properties. Library-based converters such as DomPDF implement their own CSS engine and do not support flexbox or grid.
Can an HTML to PDF API run JavaScript before printing?
Yes, if it uses a real browser. Options like wait_until, wait_for_selector and delay let charts and client-rendered content finish before the PDF is captured.
Is it better to use Puppeteer or an HTML to PDF API?
Both use Chromium, so output quality is similar. Puppeteer gives full control and keeps data in-house but means operating browsers in production; an API removes that work in exchange for a network call and usage-based cost.
Can I convert a localhost page with an HTML to PDF API?
No. A hosted API cannot reach localhost or private network addresses. Render the page to an HTML string on your server and send that instead, or expose a public, signed URL.
How is an HTML to PDF API usually priced?
Usually by usage: per request, per document or per rendered page. htmltopdfapi.co counts each rendered PDF page, with a free tier of 200 pages per day and a Pro plan of 50,000 pages per month for $29.
Related reading
Sources
Written by The htmltopdfapi.co team
Written by the engineers who build and run htmltopdfapi.co and maintain the official PHP/Laravel SDK. We ship PDF-heavy features — invoices, reports and certificates — every day, and every guide here comes from that work.