HTML to PDF, over an API
A URL or raw markup in, a PDF out, in one call. Page ranges, real header and footer templates, document metadata — and the four things about printing from a browser that catch everyone out.
The smallest version
curl -X POST https://api.getsnap.dev/v1/screenshot \
-H "X-API-Key: sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://example.com", "format": "pdf" }'
That is the whole thing. A4, portrait, 20px margins, backgrounds printed. Everything below is about the cases where those defaults are wrong.
From markup you already have
Most PDF work is not "turn this public page into a PDF" — it is an invoice, a report or a certificate rendered from a template you hold. You do not need to host it first. Send the markup instead of a URL, up to 500,000 characters:
{
"html": "<h1>Invoice 2026-0416</h1><p>Due 14 November</p>",
"format": "pdf",
"pdf_page_size": "A4"
}
Stylesheets, images and web fonts referenced by absolute URL are still fetched, so a template that pulls in Inter from a CDN renders with Inter. Relative URLs have nothing to resolve against, so make them absolute.
The four things that catch everyone out
1. Your backgrounds disappear
Chromium does not print background colours or images by default — it is a browser, and the assumption is that you are about to spend ink. A PDF of a page with a dark header comes back with a white one, and the usual reaction is that the renderer is broken.
This API sets pdf_background to true by default
because a PDF is a document rather than a print job. If you are driving
Chromium yourself, that is printBackground: true and it is off
until you say so.
2. The page looks nothing like your browser
Printing switches the page to its print stylesheet. Every rule inside an
@media print block applies, and anything scoped to
screen stops. For an invoice that is exactly right. For a
marketing page with a nav bar hidden at print time it is a surprise.
{ "url": "...", "format": "pdf", "media_type": "screen" }
"screen" forces the on-screen rendering. "print"
forces the print one even where a browser might not. Left empty, the page gets
whatever Chromium would normally use when printing.
3. Your header is there but invisible
This one costs people an afternoon. Chromium renders header and footer templates at a font size of zero unless the template sets one itself. The markup is in the document, the element exists, nothing is drawn.
The second half is margins: the header and footer are painted inside the page margin, so a 20px top margin cannot hold a 30px header. Both have to be right before anything appears.
{
"url": "https://example.com/report",
"format": "pdf",
"pdf_show_header": true,
"pdf_header": "<div style='font-size:10px; width:100%; padding:0 15mm; color:#666'>Quarterly report</div>",
"pdf_show_footer": true,
"pdf_footer": "<div style='font-size:10px; width:100%; padding:0 15mm; text-align:right; color:#666'>Page <span class='pageNumber'></span> of <span class='totalPages'></span></div>",
"pdf_margin_top": "25mm",
"pdf_margin_bottom": "20mm"
}
Chromium fills five special classes for you inside those templates:
pageNumber, totalPages, date,
title and url. Put an empty
<span> with the class where you want the value and it is
substituted per page.
4. The document has no title
Open a generated PDF and most viewers show the filename, or nothing, where the title should be. That is because Chromium writes no document metadata at all — no title, author, subject or keywords. It cannot: those live in the PDF trailer, which is written after rendering finishes.
So they have to be applied to the finished document as a second step. That is the reason most screenshot APIs do not offer them, and why this one does:
{
"url": "https://example.com/invoice/2026-0416",
"format": "pdf",
"pdf_title": "Invoice 2026-0416",
"pdf_author": "Example Ltd",
"pdf_subject": "Invoice for October 2026",
"pdf_keywords": "invoice, 2026, october",
"pdf_creator": "billing-service"
}
It matters more than it sounds for anything that gets filed: a document management system, an email client previewing an attachment, and a search index all read the title before they read a byte of the content.
Page ranges
A long report where you only want the summary, or an invoice where the terms and conditions run to four pages nobody needs. Same syntax a print dialog uses:
{ "url": "...", "format": "pdf", "pdf_page_range": "1-3, 8, 11-13" }
Paper, orientation, margins, scale
| Option | Values | Default |
|---|---|---|
pdf_page_size | A0–A6, Letter, Legal, Tabloid, Ledger | A4 |
pdf_orientation | portrait, landscape | portrait |
pdf_margin_top and the other three | any CSS length — 20mm, 0.5in, 40px | 20px |
pdf_scale | 0.1 to 2 | 1 |
pdf_background | true, false | true |
pdf_scale is the one worth knowing about: at 0.8 a
table that was spilling onto a second page often stops doing so, and it is far
less work than rewriting the CSS.
What the other APIs do
Checked against each provider's own documentation on 25 October 2026, and written up with the rest in the sourced comparison.
| Page ranges | Header / footer | Document metadata | |
|---|---|---|---|
| getSnap.dev | yes | yes | yes |
| Urlbox | yes | yes | no |
| ScreenshotAPI.net | yes | no | no |
| ScreenshotOne | no | no | no |
| ApiFlash | no PDF output at all — PNG, JPEG and WebP only | ||
Margins and paper size are universal; everyone has those. The three columns above are where the field thins out, and all three together is the part we have not found anywhere else.
Frequently asked questions
Why is my header or footer invisible?
Two reasons, usually both at once. Chromium renders those templates at font
size zero unless the template sets one, and they are drawn inside the page
margin, so a margin smaller than the header leaves it nowhere to go. Set an
explicit font-size and a margin at least as tall.
Why are my background colours missing?
Chromium does not print backgrounds by default. This API turns it on; if you
are driving the browser yourself, that is printBackground: true.
Why does the PDF look different from the browser?
Printing applies the print stylesheet. Set media_type to
screen if you want what you see on screen.
Can I build a PDF from HTML I have not published?
Yes — send it in html instead of url, up to
500,000 characters. Reference assets absolutely so they resolve.
How is this billed?
A PDF is one credit, the same as a screenshot, and a cache hit is free. A report you need every Monday can run on a schedule rather than a cron job you maintain. The free plan is 100 a month and every option on this page works on it — we meter credits, not features.
Render one and look at it
100 PDFs a month, free and permanent, no card. The full option list is in the API reference.
Get a free API key