· Comparisons · By Simon Chiu

Best OG Image Generators (2026): 8 Approaches Compared

Eight ways to generate Open Graph images compared: HTML renderers, Satori, template editors, Cloudinary and Puppeteer. Scored checklist and October 2026 prices.

Disclosure: I build RenderScreenshot, one of the eight options below. To keep that bias visible, here is exactly what this comparison is based on. I ran two engines myself on 2026-10-18: Satori (the engine in @vercel/og) and Chromium, on six identical card templates, with results and timings published below. For the six hosted services, I read their API docs and pricing pages on 2026-10-15 to 2026-10-18 and wrote a minimal request for each from those docs. I have no accounts with them, so those requests are not tested and there are no vendor renders on this page. Where a service wins, I say so.

Every OG image generator does the same job: take some data (a title, an author, a photo) and return a 1200×630 image a crawler can fetch. They differ in two things that matter more than any feature list: where the template lives (your code, a design editor, a URL) and which layout engine draws it (a real browser, a CSS subset, an image CDN). Pick those two and the shortlist is usually one or two names.

The eight options at a glance

Option Template lives in Layout engine og:image-ready URL Sync response Free tier or cost to start
RenderScreenshot Your HTML (URL or string) Chromium Signed URL, all plans Yes 150 credits/month
HTML/CSS to Image (HCTI) Your HTML, or their templates Chrome Hosted image URL after an API call; templated URLs Yes (JSON with URL) 50 images/month
ScreenshotOne Your HTML or URL Chromium Signed links Yes 100/month
@vercel/og / next/og JSX in your repo Satori + resvg A route on your site Yes Free library; your Vercel plan
Satori, self-hosted JSX in your repo Satori + resvg A route you host Yes Free; your compute
Bannerbear Their visual editor Their renderer Instant URLs (Scale plan and above) Async by default; sync endpoint 30 trial credits
Placid Their visual editor Their renderer URL API with optional signing Async by default; create_now See plans
Cloudinary A base image plus URL transformations Image CDN The transformation URL is the image Yes 25 credits/month
Puppeteer or Playwright, self-hosted Your HTML Chromium A route you host Yes Free; your servers

(That is nine rows because self-hosted Satori and @vercel/og are the same engine with different hosting; I count them as one approach.)

Best for

  • Cards that match your site, owned by developers: an HTML renderer. RenderScreenshot if you want signed og:image URLs and card presets, HCTI if you want image URLs that stay hosted without running storage, ScreenshotOne if you also need its wider screenshot option list.
  • Next.js on Vercel with simple layouts: @vercel/og. Nothing to sign up for, and fast.
  • Marketing teams that edit designs without engineers: Placid or Bannerbear. Their editors are the product.
  • A photo with a title on top, at very high volume: Cloudinary. If your assets already live there, a text overlay is one URL.
  • Full control, no third party: self-hosted Playwright or Puppeteer, if you accept running Chromium in production.

Four questions that decide it

Feature lists hide the decision. These four questions, asked in order, usually leave one or two candidates.

flowchart TD
    A{Who changes the card design?} -- Marketers, in a design tool --> B[Bannerbear or Placid]
    A -- Developers, in code --> C{Is the card a photo with a title on it?}
    C -- Yes, assets already on Cloudinary --> D[Cloudinary text overlays]
    C -- No, it is a designed layout --> E{Does the layout fit flexbox and a CSS subset?}
    E -- Yes, and you deploy on Vercel --> F["@vercel/og"]
    E -- No, or you want your site's CSS --> G{Will you run Chromium yourself?}
    G -- Yes --> H[Self-hosted Playwright or Puppeteer]
    G -- No --> I[HTML renderer: RenderScreenshot, HCTI or ScreenshotOne]

1. Who changes the design? This matters most, and it is not technical. If the people who own the brand do not write code, a template editor saves a ticket for every tweak, and nothing else on this list gives them that. If developers own it, an editor becomes one more place where the card drifts away from the site.

2. Is the card a layout or a decorated photo? A product photo with a price in the corner is an image-processing job, and an image CDN does it in one URL. A card with a heading, a byline, a logo and a background pattern is a layout job, and layouts are what HTML is for.

3. Does your layout fit Satori? Count the CSS features in your current card. If it is flexbox, solid colours, one or two fonts and some images, Satori will draw it, and @vercel/og costs you nothing extra on Vercel. If you use grid, filters, blend modes, variable fonts or a shared component library, expect to rewrite those parts for Satori, and check every render by eye, because it will not report what it skipped.

4. Will you operate Chromium? Self-hosting is cheapest per image and most expensive in attention. A sudden spike in shares means a spike in browser processes. If you already run browsers for other reasons, add cards to that fleet. If not, an HTML renderer API is the same engine without the pager.

The last branch has three names. Among them, the deciding factors are small but real: signed URLs and presets (RenderScreenshot), permanently hosted images (HCTI), or the broadest screenshot option list (ScreenshotOne).

What I tested: Satori against Chromium

The biggest technical split in this market is between real browsers and Satori. Five of the eight options render with Chromium; @vercel/og and self-hosted Satori use their own layout engine; Bannerbear, Placid and Cloudinary use renderers of their own that you never write CSS for.

To show what that split means, I wrote six cards twice, once as a Satori element tree and once as HTML, and rendered each with [email protected] plus @resvg/[email protected], and with Chromium from [email protected]. Node 22.18, Apple M1 Pro, 15 renders per template, 2026-10-18.

Template Satori Chromium
Flexbox column (section, title, byline) Correct Correct
CSS grid, 2fr 1fr columns No error; columns not split 2:1 Correct
<style> block with a class Correct Correct
Two-line clamp with ellipsis Correct Correct
Emoji and Japanese text, no extra fonts given No error; boxes for each glyph Correct (system fonts present)
backdrop-filter: blur() glass panel No error; panel opaque dark grey Correct

Median render time per card was 164 to 226 ms for Satori plus resvg and 16 to 117 ms for a warm Chromium page; launching Chromium took 404 ms once. The full table, with p95 values, file sizes and the caveats (font parsing on every Satori call, warm browser), is on the Vercel OG alternative page.

What I take from it: Satori is not slow and not broken. It is a different engine, and when it does not support something, it tends to draw something else instead of failing. If your cards stay inside its subset, it is a fine choice. If your designers write normal CSS, a browser-based option saves you from finding the differences in production.

Scored checklist

Each criterion is scored from the vendor's own docs (checked 2026-10-15 to 2026-10-18), not from my opinion. "Yes" means documented, "No" means documented as unsupported or absent, "Partial" is explained in the vendor's section, and "Not checked" means I did not find it in the docs I read.

Criterion RenderScreenshot HCTI ScreenshotOne @vercel/og Bannerbear Placid Cloudinary Self-hosted Chromium
Full browser CSS Yes Yes Yes No (subset) No (editor) No (editor) No (overlays) Yes
Templates in your repo Yes Yes Yes Yes No No Partial Yes
Visual template editor No Partial No No Yes Yes No No
URL that can go straight into og:image Yes Partial Yes Yes Partial (plan) Yes Yes Yes
Image URLs that never expire No (30 days) Yes Not checked Your CDN Yes Yes Yes Your storage
Also captures live web pages Yes Yes Yes No Partial (v2) Partial (layer) No Yes
No infrastructure to run Yes Yes Yes On Vercel Yes Yes Yes No
Free monthly allowance Yes Yes Yes n/a Trial only See plans Yes n/a

RenderScreenshot loses two rows here: there is no visual editor, and CDN links expire after at most 30 days unless you copy files into your own bucket. If either matters more to you than full CSS, pick a tool that wins that row.

Prices at three volumes

Monthly list prices in USD, as shown on each vendor's pricing page on the date given. "Fresh cards" means renders. With caching, a card is rendered far less often than it is fetched.

Option 1,000 fresh cards 10,000 fresh cards 100,000 fresh cards Checked
RenderScreenshot $10 (Starter, 2,500 credits) $40 (Growth, 12,000 credits) Above Scale's 60,000 credits ($100); contact us Pricing, 2026-10-18
HCTI $14 (Basic, 1,000) $69 (Basic, 10,000 tier) $375 (Pro, 100,000 tier) Pricing page, 2026-10-18
ScreenshotOne $17 (Basic, 2,000) $79 (Growth, 10,000) $259 for 50,000 (Scale) plus 50,000 extra at the listed $0.004 each Pricing page, 2026-10-18
@vercel/og Your Vercel function usage Your Vercel function usage Your Vercel function usage Vercel pricing
Bannerbear $49 (Automate, 1,000 credits) $149 (Scale, 10,000 credits) From $299 for 50,000 (Enterprise); higher tiers priced on the page Pricing page, 2026-10-18
Placid Plans with 500, 2,500, 25,000 and 100,000 credits a month Pricing page, prices not readable in our text capture, 2026-10-18
Cloudinary Free plan: 25 credits; 1 credit = 1,000 transformations or 1 GB of bandwidth Plus: $99 for 225 credits Pricing page, 2026-10-18
Self-hosted Your server and your time

Two billing rules change these numbers more than the list price:

  • Are repeat fetches billed? A card shared in a busy Slack workspace is fetched many times. With RenderScreenshot, a signed URL that includes cache_available=true returns the earlier render for 0 credits. On Cloudinary, the transformation is cached, but bandwidth still draws credits. Check how your vendor counts a repeat.
  • Are formats and scales multiplied? Bannerbear's docs say one render costs one credit per format, times the scale. Ask for PNG and JPG at 2x and you pay four credits.

The options in detail

1. RenderScreenshot

What it is: a screenshot API with presets for social cards. Your card is an HTML page on your site (or an HTML string); the API renders it in Chromium on Cloudflare's browser platform and returns a PNG. A signed URL goes straight into og:image.

Strengths: og_card (1200×630), twitter_card (1200×600) and twitter_card_large (1200×628) presets; signed URLs on every plan; X-Cache-URL on every response, a public CDN link you can store; repeat fetches at 0 credits with cache_available; one credit per render whatever the format; SDKs for Node, Python, Ruby, PHP, Go and Java.

Weaknesses: no visual editor; CDN links expire with the cache, 30 days at most; signed URLs must also expire within 30 days, so long-lived static HTML needs a stored copy (custom storage is on paid plans).

curl -G https://api.renderscreenshot.com/v1/screenshot \
  -H "Authorization: Bearer $RS_API_KEY" \
  --data-urlencode "url=https://example.com/og/hello-world" \
  -d preset=og_card -o card.png

This request matches our GET endpoint reference; it was not sent for this article. The OG image tutorial has the production setup with signed URLs.

2. HTML/CSS to Image (HCTI)

What it is: an HTML-to-image API. You POST HTML and CSS (or a URL) and get back JSON with a hosted image URL.

Strengths: simple API; hosted image URLs that stay live while your account is active, so no storage to run; Google Fonts by name in the request; templates with URL parameters for OG use.

Weaknesses: an API call before you have a URL, unless you use its templates; fewer page-capture options than a screenshot API.

curl -X POST https://hcti.io/v1/image \
  -u "$HCTI_USER_ID:$HCTI_API_KEY" \
  --data-urlencode 'html=<div class="card">Hello world</div>' \
  --data-urlencode 'css=.card{width:1200px;height:630px;background:#0f172a;color:#fff;font:700 64px sans-serif}'

Written from HCTI's API docs, not run. Our HCTI alternative page maps every parameter.

3. ScreenshotOne

What it is: a screenshot API with a long option list. It can render a URL or HTML and supports signed links.

Strengths: many capture options, including video output; signed links; a free monthly allowance; a cache URL header.

Weaknesses: no card presets, so you set the viewport yourself; at 1,000 cards a month you pay for its smallest plan of 2,000.

curl -G https://api.screenshotone.com/take \
  -d access_key="$SCREENSHOTONE_ACCESS_KEY" \
  --data-urlencode "url=https://example.com/og/hello-world" \
  -d viewport_width=1200 -d viewport_height=630 -d format=png -o card.png

Written from ScreenshotOne's public API docs, not run.

4. @vercel/og (and self-hosted Satori)

What it is: Vercel's library that turns JSX into PNG with Satori and resvg. It is built into the Next.js App Router as next/og, and Satori itself runs anywhere Node runs.

Strengths: free; fast to start; no third party; the image is generated next to your data; cache headers set for you on Vercel.

Weaknesses: a CSS subset (flexbox, no grid); Vercel lists a 500 KB bundle limit that includes fonts; fonts must be ttf, otf or woff; unsupported CSS fails silently, as the test above shows.

// app/og/route.tsx
import { ImageResponse } from 'next/og';

export async function GET() {
  return new ImageResponse(
    <div style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'center',
      justifyContent: 'center', background: '#0f172a', color: '#f8fafc', fontSize: 64 }}>
      Hello world
    </div>,
    { width: 1200, height: 630 },
  );
}

Follows Vercel's OG docs. I rendered the same engine through satori directly; I did not deploy this route. The Vercel OG alternative has the test results.

5. Bannerbear

What it is: a template image platform. Design a template in its editor, then POST modifications to fill named layers. It also does animations, workflows and AI image tools.

Strengths: a visual editor for non-developers; hosted files; Instant URLs for og:image; many output formats including AVIF and PDF.

Weaknesses: async by default (the sync endpoint has a 10-second limit); credits multiply by format and scale; Instant URLs and custom S3 start at the Scale plan; templates live outside your repo.

curl -X POST https://api.bannerbear.com/v5/images \
  -H "Authorization: Bearer $BANNERBEAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"template": "TEMPLATE_UID", "modifications": {"objects": [{"name": "title", "text": "Hello world"}]}}'

Written from Bannerbear's v5 API reference, not run. The Bannerbear alternative shows how to rebuild a template in HTML and keep the modifications array.

6. Placid

What it is: another template editor with an API. Its URL API builds an image from query parameters, with an optional HMAC signature, which makes it easy to put in og:image.

Strengths: URL API on top of a visual editor; simple credit rule (one image, one credit, per its docs); a browserframe layer can place a website screenshot inside a design.

Weaknesses: templates live in its editor (the Placid alternative shows how to rebuild them as HTML); prices were not readable in our text capture of its pricing page, so check them yourself.

https://api.placid.app/u/{template_uuid}?title[text]=Hello%20world

The URL shape follows Placid's URL API docs: the layer name, then the property in brackets. Not run. Our Bannerbear vs Placid comparison goes deeper on both.

7. Cloudinary

What it is: an image CDN and media platform. With text overlays, the URL itself describes the card: a base image, a size and one or more text layers.

Strengths: no template service at all if your assets are already on Cloudinary; the URL is the image; global CDN delivery.

Weaknesses: layout is limited to what overlays can express (position, font, colour, wrapping width); long titles need careful URL encoding; credits count bandwidth as well as transformations.

https://res.cloudinary.com/<cloud_name>/image/upload/w_1200,h_630,c_fill/l_text:Arial_64_bold:Hello%20world,co_white,w_1000,c_fit/fl_layer_apply,g_west,x_80/<base_image_id>.jpg

Built from Cloudinary's transformation reference; not run against an account. Check the text-overlay rules in Cloudinary's docs for escaping commas and slashes in titles. If you use Cloudinary for website screenshots rather than cards, see the Cloudinary screenshot alternative.

8. Puppeteer or Playwright, self-hosted

What it is: your own Chromium, driven by code, behind a route on your server.

Strengths: full CSS; no vendor; no per-image price.

Weaknesses: you run Chromium in production: memory, crashes, zombie processes, fonts on Linux, a queue for traffic spikes. Each of those is solvable, and each is your job. The Puppeteer alternative page and the guide to scaling Puppeteer screenshots cover what that takes.

import { chromium } from 'playwright';

const browser = await chromium.launch();
try {
  const page = await browser.newPage({ viewport: { width: 1200, height: 630 } });
  await page.goto('https://example.com', { waitUntil: 'load' });
  await page.screenshot({ path: 'card.png' });
} finally {
  await browser.close();
}

I ran this listing against https://example.com on 2026-10-18 with [email protected] (same API as the playwright package; import from playwright-core if you manage browsers yourself). It wrote a 1200×630 PNG.

How to run your own evaluation

Vendor pages, this one included, cannot tell you how your own template renders. A fair evaluation takes an afternoon:

  1. Pick five real cards, not demo cards: your longest title, a title with emoji, one with non-Latin text, one with a photo, and your plainest one.
  2. Build the template once per model. For HTML renderers, it is one HTML file. For Satori, the same design as JSX. For editors, rebuild it in the editor.
  3. Render all five with each candidate and put the results side by side. Look for wrapped titles, missing glyphs and layout shifts. Our Satori vs Chromium script is a starting point for the code-based options.
  4. Paste one URL from each candidate into a private Slack channel and check the preview. That is what your users see.
  5. Price it with your real numbers: fresh cards per month, not shares.

If you want a free key for step 3, sign up and use the OG image API with the og_card preset.

Changelog

  • 2026-10-18: First version. Satori and Chromium tested on six templates; hosted vendors compared from their docs and pricing pages. Vendor renders and a hosted-latency benchmark are not included yet; they will be added only after a run with real accounts, with the raw data.

Related in this topic