Use POST /v1/images when you need a png, jpeg, or webp screenshot of HTML or a public URL. That is not a PDF. RelayPDF runs the same Chromium engine as POST /v1/pdf, then writes a bitmap instead of a print surface. Product page: https://relaypdf.com/screenshots. Field list: https://relaypdf.com/docs/images.
What this endpoint is not
POST /v1/pdf prints a document. POST /v1/pdf/raster turns existing PDF pages into PNG or JPEG. POST /v1/images screenshots HTML or a live public URL. If you already have a PDF and want page previews, use raster. If you need invoices, page numbers, or headers, stay on /v1/pdf.
Exactly one of html or url. Sending both, or neither, is invalid_request. Private, loopback, and metadata hosts on url are url_not_allowed. Markdown and templateId are PDF-only; they are not image sources.
First request
Bearer key. JSON body. Default type is png. Default fullPage is false, so you get the viewport, not the scroll height. The product curl writes a full-page PNG from a URL:
curl https://api.relaypdf.com/v1/images
-H "Authorization: Bearer pdf_live_..."
-H "Content-Type: application/json"
-d '{"url":"https://example.com","options":{"fullPage":true}}'
--output page.png
response defaults to binary. Successful bytes carry x-relaypdf-id, x-relaypdf-size, and content-disposition. Set response to url for a 24-hour GET /v1/files/:id link (no key on download). Set response to async for HTTP 202 and GET /v1/jobs/:id. callbackUrl, if present, must be https.
Viewport versus full page
options.viewport is width, height, and optional deviceScaleFactor. Omit it and Chromium uses its default viewport. fullPage false (the default) captures that box. fullPage true captures the scrollable page. clip is a crop box: x, y, width, height. captureBeyondViewport, documented on rendering options, includes content outside the viewport when you set it.
Pick viewport when you want a card, a hero, or a fixed dashboard tile. Pick fullPage when the page is a long landing or a report that does not fit one screen. Clip after the fact if you only need a region. Do not invent units beyond the documented numbers; width and height are integers on viewport and numbers on clip.
png, jpeg, webp
options.type is png (default), jpeg, or webp. filename, if you send it, must match the type: .png, .jpg or .jpeg, .webp. quality is 1–100 and applies to jpeg and webp only. omitBackground defaults to false; set true for a transparent PNG when Chromium supports it. Field names are identical in JSON, Node, and Python (fullPage, not full_page).
deviceScaleFactor on viewport is the retina-style multiplier. A 1280×720 box at 2 yields a denser bitmap. There is no documented default for an omitted viewport, so set width and height when the crop must be exact. JPEG is lossy; keep png when you need a lossless card or a transparent background.
{
"html": "<html><body style=\"margin:0\"><h1>Card</h1></body></html>",
"filename": "card.webp",
"options": {
"type": "webp",
"quality": 80,
"fullPage": false,
"viewport": { "width": 1280, "height": 720, "deviceScaleFactor": 2 }
}
}
Wait for the page
waitUntil and timeout are the same fields as POST /v1/pdf. waitUntil defaults to networkidle0 on the rendering-options page. Documented lifecycle values on the OpenAPI waitUntil enum (shared with PDF) are load, domcontentloaded, networkidle0, and networkidle2. timeout is milliseconds, max 60000. That budget is Chromium render time, not an SDK HTTP timeout.
PDF and image options also document extraHTTPHeaders, cookies (name, value, optional domain/path/url), waitForSelector, and waitForTimeout (extra wait in ms, max 30000). Use those when a chart paints after network idle. Jobs that fail to render return render_failed and are not billed.
{
"url": "https://example.com/dashboard",
"filename": "dash.png",
"options": {
"type": "png",
"fullPage": true,
"waitUntil": "networkidle0",
"timeout": 30000
}
}
HTML string versus public URL
html is a UTF-8 JSON string, same rule as PDF: not Base64. Use it when the markup is yours and you do not want a public fetch. url is for a page RelayPDF can reach on the public internet. Cookies and extraHTTPHeaders apply to the Chromium fetch of that URL. They do not punch through to RFC1918 hosts.
Query-string keys are rejected. Authorization is Bearer only. GET /health is unauthenticated liveness. GET /v1/account returns plan, rate tier, and wallet millicents and is not billed. Same key covers REST, SDKs, CLI, and MCP.
CLI, SDK, MCP
CLI maps image --url or --html to POST /v1/images. The documented full-page example is relaypdf image --url https://example.com --full-page --out page.png. Node: client.images.fromUrl or fromHtml, plus images.create for a raw body. Published screenshot sample:
const shot = await client.images.fromUrl("https://example.com", {
options: { fullPage: true, type: "png" },
});
await shot.save("page.png");
Python: client.images.from_url(..., options={"fullPage": True}) or from_html. MCP tool name is image. Same bearer key as PDF. Do not ask a human to paste a key; run npx @relaypdf/cli setup.
Screenshot versus raster
| Job | Endpoint | Source | Typical debit |
|---|---|---|---|
| Screenshot | POST /v1/images | html or url | $0.015 |
| Print PDF | POST /v1/pdf | html, url, markdown, templateId | $0.015 |
| Raster pages | POST /v1/pdf/raster | existing PDF | $0.005 |
| Images → PDF | POST /v1/pdf/from-images | PNG/JPEG files | tools rate |
Raster default is page 1; multiple pages return a zip. That is a different worker path (document worker / pdftoppm). Screenshots bill as a Chromium image job at the launch screenshot rate. Failed operations, 429s, and 402s are never billed. Trial wallets: 20 requests/minute. Funded or auto-reload: 60/minute. Burst: 5 / 10 seconds.
Errors you will actually see
invalid_request for exclusive sources or a filename that does not match type. unauthorized for a missing or unknown key. payment_required when the wallet is empty. rate_limited with Retry-After. payload_too_large if HTML is oversized (no published megabyte figure). render_failed if Chromium could not capture the page. Branch on error.code, not the status text.
When to stop and print a PDF instead
A screenshot is a picture of one viewport or one scroll. It has no searchable text layer, no page numbers, and no print CSS page boxes. Use POST /v1/pdf when the artifact is an invoice, a contract, or anything a human will print. Use /v1/images when you need an OG image, a visual regression sample, a Slack preview, or a WebP card. Sibling wait-for-JS notes for PDF apply the same waitUntil field: https://relaypdf.com/blog/html-to-pdf-wait-for-javascript.
Ship it
Create a key, POST html or url to https://api.relaypdf.com/v1/images, set type and fullPage, then decide jpeg/webp quality if you are not staying on png. Product and playground: https://relaypdf.com/screenshots. Options table: https://relaypdf.com/docs/images and https://relaypdf.com/docs/options. OpenAPI: https://relaypdf.com/openapi.json.