Best HTML to Image APIs (2026): 9 Options Compared
The best HTML to image APIs compared: rendering engine, ready signals, fonts, delivery, public links and prices at three volumes, from each vendor's own docs.
Disclosure: I build RenderScreenshot, one of the APIs on this list. Facts about other vendors come from their public docs and pricing pages, checked between 14 and 18 October 2026 for our alternative pages, and each section links to the page with the full mapping. Method: we compared what each service documents on six points that decide whether an HTML template renders correctly and stays cheap: rendering engine, ready signal, fonts and assets, transparency, delivery and public links, and price at 1,000, 10,000 and 100,000 images a month. We also ran 19 CSS pixel probes against the two rendering engines that these services use. What is missing: the planned benchmark of six templates through every API has not run yet, so this page has no latency or success-rate numbers per vendor.
If you only want the short answer: for HTML you keep in your own repository, use a Chrome-based API whose ready signal and link model fit your pages. Use a visual template tool when non-developers own the design, and use self-hosted Playwright when no third party may see the data.
The nine options at a glance
| Service | Engine | HTML input | Ready signal | Transparent | Delivery | 1,000 / month | 10,000 / month | 100,000 / month |
|---|---|---|---|---|---|---|---|---|
| RenderScreenshot | Chrome | html + html_base_url |
wait.for_selector, wait.until |
output.transparent |
Image bytes + X-Cache-URL CDN link; signed GET URLs |
$10 (Starter) | $40 (Growth) | Above Scale's 60,000; contact us |
| HTML/CSS to Image | Chrome | html + separate css |
render_when_ready + ScreenshotReady() |
transparent_background |
Hosted image URL | $14 (Basic) | Basic, 10,000 tier on its slider | Pro, 100,000 tier (Pro from $149 for 30,000) |
| Urlbox | Chrome | html |
wait_for selector |
transparent |
Signed render links; sync endpoint returns a URL | $19 (Lo-Fi) or $49 (Hi-Fi) | $99 (Ultra) | $795 (Business) |
| ScreenshotOne | Chrome | html, markdown |
wait_for_selector |
omit_background |
Image bytes; opt-in cache link | $17 (Basic) | $79 (Growth) | $459 (Scale + extra) |
| Browserless | Chrome (also Firefox, WebKit for sessions) | html on /screenshot |
waitForSelector, waitForFunction |
options.omitBackground |
Image bytes | Free tier (1,000 units) | $25 (20,000 units) | $140 (180,000 units) |
| Cloudflare Browser Rendering | Chrome | html on /screenshot |
waitForSelector |
screenshotOptions.omitBackground |
Image bytes | $5 (Workers Paid) | about $5 to $7 | about $9 to $29 |
| Bannerbear | Its own template renderer | No; templates from its editor | Not needed (no page scripts) | See vendor | Hosted image URL | $49 (Automate) | $149 (Scale) | Enterprise, from $299 for 50,000 |
| Placid | Its own template renderer | No; templates from its editor | Not needed | See vendor | Hosted image URL; URL API | See its pricing page | See its pricing page | See its pricing page |
| @vercel/og (library) | satori + resvg | JSX with inline styles | Not needed (no scripts) | Yes, by default | Your function's response | Function cost only | Function cost only | Function cost only |
Prices are list prices for monthly billing as recorded on our alternative pages. Urlbox's Lo-Fi plan has usage restrictions described on its pricing page. Browserless figures assume each render fits in one unit of up to 30 seconds. Cloudflare figures are our estimates at 2 and 10 seconds of browser time per image. Self-hosted Playwright is the baseline in the last section; it is not in the table because its cost is your servers and your time.
Why most Chrome-based APIs render CSS the same
An HTML to image API is a browser plus a contract. The browser does the layout. When six of these services run Chrome, their CSS support is Chrome's CSS support, give or take a few versions.
We checked how much the engine matters with 19 pixel probes, each a tiny document that shows green only when a CSS feature works. Headless Chromium passed all 19. satori, the engine inside @vercel/og, passed 14: it has no custom properties and reads no stylesheets, so :has(), container queries and nesting cannot apply. The full method and table are in render HTML to PNG.
So for Chrome-based APIs, the CSS question becomes three smaller ones:
- When does the capture happen? Too early, and fonts, images or chart data are missing.
- Which fonts are installed? Text without a web font falls back to whatever the provider's servers have.
- Which Chrome version runs? New CSS, such as recent colour functions, arrives with new Chrome releases.
Those are what the sections below compare.
Five differences that matter more than CSS
Once the engine is Chrome, these are the points where HTML to image APIs really differ. Check each one against your templates before you compare prices.
1. How the API knows your page is ready. A static card is ready at the load event. A card that fetches data, draws a chart or swaps in a web font is not. There are three designs. A function call (HCTI's ScreenshotReady()) is exact, but your template must call a vendor-specific function. A selector wait (RenderScreenshot, Urlbox, ScreenshotOne, Browserless, Cloudflare) is exact and vendor-neutral: your page adds an element or attribute when it is done, and the same template works with any of them and with local Playwright. A fixed delay is what you use when neither exists, and it is either slow or wrong. Prefer the selector wait, and set the marker after document.fonts.ready.
2. How fonts get into the image. Every API renders the fonts your HTML loads, if they finish loading before the capture. Some add a shortcut: HCTI's google_fonts parameter writes the stylesheet link for you. Shortcuts are convenient but tie the template to one vendor. A <link> to the font in the HTML, with font-display: block, works everywhere. For text in scripts such as Chinese, Japanese or emoji, do not rely on the fonts installed on the provider's servers; load them yourself.
3. How relative assets resolve. HTML that you send has no address, so /img/logo.svg points nowhere. RenderScreenshot has html_base_url for this. With other APIs, use a <base> element or absolute URLs. Either way, assets must be reachable from the provider's servers. RenderScreenshot refuses private addresses such as localhost and 10.x.x.x, so the API cannot be used to reach internal networks; check how any other vendor treats them before you rely on an internal asset host.
4. What comes back. There are two response models. Bytes (RenderScreenshot by default, ScreenshotOne, Browserless, Cloudflare) are simplest when your code stores the image. A hosted URL (HCTI, Bannerbear, Placid, Urlbox's sync endpoint) is simplest when you only need a link, but adds a second request when you need the file. RenderScreenshot does both: the body is the image, and the X-Cache-URL header is a CDN link to the same file.
5. How an image URL can live in public HTML. An og:image tag or an <img> in an email is fetched by crawlers and email clients, not by your server. That URL must not contain a secret key. The options are signed links (RenderScreenshot, Urlbox, Placid's signed-only mode), hosted URLs of images rendered in advance (HCTI, Bannerbear), or your own route that renders and caches. Note the expiry rules: RenderScreenshot signed URLs expire after at most 30 days, while Urlbox render links have no expiry in the token.
Best for, by job
| Job | Pick | Why |
|---|---|---|
| Social cards and OG images from HTML in your repo | RenderScreenshot or Urlbox | Signed GET URLs can sit in an og:image tag without exposing a key |
| Templates edited by designers, not developers | Bannerbear or Placid | The template lives in a visual editor and code fills named layers |
| Existing HCTI templates with Handlebars | HTML/CSS to Image | Templates and versions are stored by the API |
| Many output formats (AVIF, GIF, Markdown) | ScreenshotOne | The widest format list of the Chrome-based options here |
| Custom browser code next to the screenshot | Browserless or Cloudflare Browser Rendering | You get sessions, not only an image endpoint |
| Next.js app with flexbox-only cards | @vercel/og |
No third party, fast cold start, if satori's CSS is enough |
| Data that may not leave your network | Self-hosted Playwright | Nothing leaves your servers |
Reading the price table
List prices hide the counting rules, and the rules decide the bill. Four questions to ask each vendor:
- What counts as one image? RenderScreenshot charges one credit per successful render, whatever the size or format. Urlbox counts extra renders for long render times, large files, GPU use and proxies. Browserless and Cloudflare bill browser time, so a template that waits two seconds for a chart costs more than one that is ready at once.
- Do failures cost anything? On RenderScreenshot, no: timeouts, navigation errors and missing selectors use no credit. Check this for every vendor, because strict ready checks fail on purpose when a template is broken.
- Are repeat requests free? An
og:imageURL is fetched by every crawler. With RenderScreenshot,cache.availablereturns an identical earlier render for 0 credits, and theX-Cache-URLlink costs nothing to load. A hosted-URL vendor charges once per created image, and the link is free after that. - What happens at the limit? RenderScreenshot stops with an
insufficient_creditserror and never bills overage. ScreenshotOne bills extra images. HCTI's overage is optional and off until you enable it. Placid stops generating.
Run your real monthly volume through these four questions before you compare the headline prices.
The checklist, scored
Each row is a yes or no from the vendor's documentation. "Docs" means we found the feature documented; we have not tested every one against the live service.
| Criterion | RenderScreenshot | HCTI | Urlbox | ScreenshotOne | Browserless | Cloudflare | Bannerbear | Placid | @vercel/og |
|---|---|---|---|---|---|---|---|---|---|
| Real browser engine | yes | yes | yes | yes | yes | yes | no | no | no |
| Raw HTML input | yes | yes | yes | yes | yes | yes | no | no | JSX |
| Wait for a selector | yes | via function call | yes | yes | yes | yes | n/a | n/a | n/a |
| Transparent output | yes | yes | yes | yes | yes | yes | see vendor | see vendor | yes |
| PDF from the same request | yes | yes | yes | yes | not on /screenshot |
not on /screenshot |
see vendor | see vendor | no |
Public link safe for <img> |
signed URL, 30 days max | hosted URL | signed link | opt-in cache link | no | no | hosted URL | URL API | your route |
| Free monthly allowance | yes | yes | trial only | yes | yes | Workers Free, daily minutes | no | see vendor | n/a |
Two rows need a note. For Browserless and Cloudflare, "no public link" means the API returns bytes to your code, and you host the image. That is fine for server-side jobs and extra work for og:image tags. For Bannerbear and Placid, "see vendor" means our pages did not record the feature; check their docs. Placid's prices load with JavaScript and we could not read them.
RenderScreenshot
What it is: our API. Rails handles keys, validation, caching and billing. Rendering runs in Chrome on Cloudflare's Browser Rendering, and images go straight to R2 storage behind a CDN.
Strengths: html_base_url for relative assets; wait.for_selector with visible, hidden, attached and detached modes; output.transparent for PNG and WebP; PNG, JPEG, WebP and PDF from the same request. Every image response carries an X-Cache-URL CDN link. Signed URLs let a GET request sit in public HTML for up to 30 days. Failed renders cost no credit.
Weaknesses: no stored template engine, so variables are filled in your code; no video, GIF or AVIF output; no self-serve plan above Scale's 60,000 credits; and signed URLs expire after at most 30 days, so static pages need a rebuild or a redirect route.
curl -X POST https://api.renderscreenshot.com/v1/screenshot \ -H "Authorization: Bearer $RS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "html": "<!doctype html><html><body style=\"margin:0;width:1200px;height:630px;display:grid;place-items:center;background:#0f172a;color:#fff;font:700 64px system-ui\">Release 2.4</body></html>", "viewport": { "width": 1200, "height": 630 }, "output": { "format": "png" } }' \ -o card.png
The HTML to image guide covers fonts, base URLs and escaping.
HTML/CSS to Image (HCTI)
What it is: a long-running API built for exactly this job. You send html and a separate css string, and get JSON with a hosted image URL.
Strengths: templates with Handlebars variables that you can create and version through the API; a google_fonts parameter that loads fonts for you; device_scale from 0.1 up, useful for thumbnails; a ready signal through a ScreenshotReady() call in your page. Images stay at their hosted URL, so there is nothing to refresh.
Weaknesses: the ready signal is a function call, not a selector, so templates must know about HCTI. It has no networkidle-style wait. Every request is a two-step flow if you need the bytes: create, then download.
curl -X POST https://hcti.io/v1/image \ -u "$HCTI_API_ID:$HCTI_API_KEY" \ -d html='<div class="card">Release 2.4</div>' \ -d css='.card { font: 700 64px sans-serif; padding: 80px }'
The parameter-by-parameter map is on our HTML/CSS to Image alternative page, and HCTI vs Bannerbear compares it with an editor-based tool.
Urlbox
What it is: a mature screenshot API with a large option set, including HTML input and output formats such as SVG, MP4 and Markdown.
Strengths: signed render links with no expiry in the token, which suits static sites that bake image URLs into HTML for months; wait_for and fail_if_selector_missing; many PDF options.
Weaknesses: no free tier, only a 7-day trial; the cheapest plan has usage restrictions; and its pricing footnotes add renders for long render times, large files, GPU use and proxies. Read them before you estimate.
The sync endpoint returns a renderUrl that you download in a second request. Our Urlbox alternative page has an adapter in Node, Python and Ruby, written from its docs.
ScreenshotOne
What it is: a screenshot API with html and markdown input and a long list of output formats.
Strengths: formats beyond the usual four, including AVIF, GIF, TIFF and HEIF; wait_for_selector and error_on_selector_not_found; a free plan of 100 screenshots a month; extra screenshots billed per image instead of a hard stop.
Weaknesses: the default format is JPEG, so set PNG for text-heavy cards; its cache link is opt-in, defaults to 4 hours and, by its own docs, is not meant for CDN-style use; we found no cache purge endpoint. See the ScreenshotOne alternative for the full mapping.
Browserless
What it is: hosted browser infrastructure. Most customers connect Puppeteer or Playwright to it, and its REST /screenshot endpoint takes html or url with Puppeteer-style options.
Strengths: the full Puppeteer option set, including waitForFunction; the same account runs multi-step browser sessions when an image is one step of a longer flow; Firefox and WebKit for sessions.
Weaknesses: you host and cache the images yourself, and billing is in units of browser time, so slow templates cost more. Details and a migration script are on the Browserless alternative page.
Cloudflare Browser Rendering
What it is: Chrome inside Cloudflare's network, driven from a Worker or through REST "Quick Actions", one of which is /screenshot with html or url.
Strengths: very low cost at volume because you pay for browser time, not per image; close to R2 and Workers if you already use them. RenderScreenshot itself renders on this platform, so we know it well.
Weaknesses: it is a building block. Keys per customer, caching, public links, retries and storage are yours to build. Our Cloudflare Browser Rendering alternative page has the cost formula and a Worker with both backends.
Bannerbear
What it is: a template tool. Designers build a template in Bannerbear's editor, and your code fills named layers through a modifications array.
Strengths: non-developers own the design; no HTML, fonts or ready signals to manage; a synchronous endpoint when you need the image in the same request.
Weaknesses: it does not take HTML, so your site's components and CSS cannot be reused. At 1,000 images a month it is, with Urlbox Hi-Fi, the most expensive option in the table. The Bannerbear alternative page shows how to rebuild a template as HTML if you outgrow the editor.
Placid
What it is: another template tool, with an embeddable editor SDK so your own users can edit templates inside your app.
Strengths: the embeddable editor is unusual on this list; a URL API for <img> tags with an optional signed-only mode; unused credits roll over up to twice the monthly amount, as described in its docs.
Weaknesses: no HTML input, and its URL API works without authentication unless you turn on signed-only mode. Check that setting before template IDs appear in public HTML. See Placid vs HTML/CSS to Image.
@vercel/og
What it is: not an API but a library. It runs satori and resvg inside your own function, and is built into Next.js as next/og.
Strengths: no third party, no per-image fee and a fast cold start.
Weaknesses: satori's CSS subset. In our probes it had no custom properties and no stylesheets, so you write cards for satori with inline styles, not for the web. If you find yourself designing around the renderer, the @vercel/og alternative page explains how to move to HTML.
Baseline: self-hosted Playwright
Everything above competes with about twenty lines of Playwright: page.setContent(html), wait for a ready selector, page.screenshot(). It passed all 19 CSS probes, because it is the same engine. The costs are elsewhere: a Chrome install, fonts on Linux, memory, stuck processes, and a cache and public URL scheme of your own. The Puppeteer setContent guide shows that path with timings, and the screenshot API vs self-hosted cost post puts numbers on the servers.
How to run your own evaluation
Until our cross-vendor benchmark runs, do this with your real templates:
- Pick five templates that use your real fonts, images and CSS, including one with a chart or data loaded by script.
- Add a ready marker to each, such as
data-readyon<body>, set afterdocument.fonts.readyand any data fetch. - Render each template three times per vendor with the vendor's ready signal, at the same viewport and scale.
- Record time to first byte, total time, bytes, and whether the image matches a local Playwright render. A pixel diff with a small threshold is enough.
- Check the price at your real monthly volume, including each vendor's counting rules for retries, long renders and cache hits.
The CSS probe harness from render HTML to PNG adds a quick check that a vendor's Chrome version supports the CSS your templates use. Our best screenshot API comparison has a multi-vendor script for live URLs that you can adapt to HTML input.
To run the same steps against RenderScreenshot, create a free account; the Free plan's 150 monthly credits cover a five-template test several times over.
Changelog
- 2026-10-18: First version. Vendor facts from docs and pricing pages checked 14 to 18 October 2026; CSS probes run locally. The cross-vendor template benchmark is still to come, and this page stays a draft until it has run.
Related in this topic
- HTML to Image API: Render HTML and CSS to PNG Send HTML and CSS, get a PNG, JPEG, WebP or PDF back from real Chrome. Base URLs for assets, web fonts, transparent backgrounds and signed URLs.
- HTML/CSS to Image Alternative: Parameter Map and Migration Moving off HTML/CSS to Image (hcti.io)? Map every create-image parameter to RenderScreenshot, keep your templates, and see where HCTI is still the better fit.
- html2canvas Alternative: Render the DOM in Real Chromium We tested html2canvas 1.4.1 against real Chromium on 14 CSS features. See what it drops, when it is still the right tool, and how to move capture server-side.
- Convert a Webpage to an Image: 5 Methods, Measured Convert a webpage to a PNG, JPEG or WebP five ways, from a DevTools command to an API. Effort, cost and timings for each, plus the settings that matter.
- HTML to Image in Node.js: 4 Ways, Same 6 Templates HTML to image in Node.js with Puppeteer, node-html-to-image, satori and an API, run on the same six templates. Measured times, what broke, and code that works.
- HTML to Image in Python: imgkit, html2image, Playwright Convert HTML to an image in Python with html2image, Playwright or an API, compared on five templates with timings and renders, and why imgkit is a dead end.