Originally published on propzapi.com — cross-posted here.
You already wrote the layout. It's a <div> with some CSS, and it looks right in your browser. Now you need it as a PNG, a few hundred times, one per row in your database. That gap, between a page you can see and an image file you can host, is the whole job.
What an HTML to image API actually does
You POST HTML (or a stored template id plus data), it renders that markup in real headless Chromium, and hands back a hosted PNG/JPEG/WebP URL. No browser to install, no canvas library, no fonts to wrangle. Your CSS in, a picture out.
The reason to reach for a service instead of a browser library like html-to-image or html2canvas: those run in the user's browser and taint the canvas the moment a cross-origin image or a webfont touches it, so the asset shows in the preview and then silently vanishes from the export. Server-side rendering sidesteps that entirely.
Why not just run Puppeteer yourself?
You can. The script is an afternoon. Then production shows up: a single headless Chrome instance runs 300–500MB of RAM and climbs past 1GB over time, needs system fonts installed, and crashes under concurrency. On Lambda the full Chromium binary blows the 250MB package limit, so you're on @sparticuz/chromium with a 2GB function and a bumped timeout. None of it is hard. It's just a browser you now operate, forever, to make pictures.
One call
curl https://api.propzapi.com/v1/images \
-H "X-API-Key: pk_live_…" -H "Content-Type: application/json" \
-d '{"template":"og-article","data":{"title":"Ship an image for every row"},"format":"png"}'
# → { "url": "https://images.propzapi.com/img_….png", "width":1200, "height":630, "bytes":95126 }
Store your own HTML once (with {{variables}}), then render it per record. Because it's full Chromium, whatever CSS works in your browser works in the image — flexbox, grid, gradients, web fonts. Not a stripped-down subset of it.
PNG, WebP or JPEG?
PNG for text and sharp edges, since it's lossless. WebP when there's a photo or a gradient in the frame (about 26% smaller). JPEG only for mostly-photo art. Set format and scale (2 for retina) per call.
When you don't need it
If you have five fixed images that never change, make them by hand in Figma and move on. An API earns its place when the images are per-record and unbounded — a card per post, an invoice per order, a certificate per user.
I wrote the full version — the self-host cost breakdown, a four-way comparison table, formats with real byte sizes, and the honest "when not to" — in the full HTML to Image API guide. It's built on propzapi, which also screenshots any URL, exports one-page PDFs, and ships an MCP server so an agent can render an image as a tool call.
Top comments (0)