Dynamic OG Images Without Puppeteer: The Satori Approach
Headless browsers like Puppeteer were the go-to for generating dynamic OG images. But they're slow, resource-hungry, and painful to deploy. There's a better way.
The Puppeteer Problem
For years, the standard approach to generating dynamic images was to spin up a headless Chrome instance with Puppeteer, render an HTML page, and take a screenshot. It works, but it comes with serious drawbacks:
- Slow: Each image takes 2-5 seconds to generate, sometimes longer on cold starts
- Resource-heavy: A Chromium binary is ~280 MB. Each instance consumes 100-300 MB of RAM
- Complex deployment: You need a server with enough memory and CPU to run headless Chrome — no serverless or edge functions
- Fragile: Browser rendering is non-deterministic. Font loading, network requests, and timing issues cause inconsistent output
- Cold start penalty: The first request after a deploy can take 10+ seconds while Chrome boots up
Enter Satori: JSX to SVG at the Edge
Satori is an open-source library created by Vercel that converts JSX (React-like components) directly into SVG — no browser needed. It implements a subset of CSS Flexbox layout in pure JavaScript/WebAssembly, which means it can run anywhere: serverless functions, edge runtimes, or even in the browser.
The pipeline is simple:
- Write your image layout as JSX with inline styles
- Satori converts the JSX to an SVG string
- A lightweight library like
@resvg/resvg-wasmconverts the SVG to PNG
The entire process happens in memory with no external dependencies.
Performance: 50ms vs 2-5 Seconds
Here's how Satori compares to Puppeteer in real-world benchmarks:
| Metric | Puppeteer | Satori |
|---|---|---|
| Average generation time | 2,000 - 5,000 ms | 30 - 80 ms |
| Cold start | 5,000 - 15,000 ms | 100 - 300 ms |
| Memory usage | 100 - 300 MB | ~10 MB |
| Binary size | ~280 MB (Chromium) | ~2 MB (WASM) |
| Edge-compatible | No | Yes |
| Deterministic output | No | Yes |
That's a 40-100x speed improvement with a fraction of the resource usage. Satori makes it practical to generate images on every request without caching.
How OGPix Uses Satori at the Edge
OGPix is built entirely on Satori and runs on Vercel Edge Functions. When you make an API request, here's what happens:
- Parse parameters: The edge function reads your title, description, theme, and other parameters from the URL
- Build JSX: A React-like component tree is constructed with your content and the selected theme/template
- Satori renders SVG: The JSX is converted to an SVG with all text, gradients, and layout computed in WASM
- Resvg converts to PNG: The SVG is rasterized to a 1200x630 PNG image
- Return response: The PNG is returned with appropriate cache headers
The entire pipeline typically completes in under 50ms at the edge, meaning your OG images are served from the closest data center to the requesting crawler with near-zero latency.
Satori's CSS Support
Satori supports a practical subset of CSS that covers most image generation needs:
- Flexbox layout: Full support for
display: flex, alignment, wrapping, and gap - Typography: Font families, sizes, weights, line height, letter spacing, text alignment
- Colors & gradients: Solid colors, linear gradients, radial gradients, opacity
- Borders & shadows: Border radius, border styles, box shadows
- Positioning: Absolute and relative positioning
- Images: Image elements with
objectFitsupport
You won't have CSS Grid or complex animations, but for OG image generation, Flexbox is more than enough.
Example: Satori JSX for an OG Image
Here's what a typical Satori template looks like:
// This JSX is converted directly to SVG by Satori
const element = (
<div style={{
display: "flex",
flexDirection: "column",
justifyContent: "center",
padding: "60px",
width: "1200px",
height: "630px",
background: "linear-gradient(135deg, #1e1b4b, #312e81)",
color: "white",
fontFamily: "Inter",
}}>
<h1 style={{ fontSize: "64px", fontWeight: 700 }}>
{title}
</h1>
<p style={{ fontSize: "28px", color: "#a5b4fc" }}>
{description}
</p>
</div>
);When Puppeteer Still Makes Sense
There are a few niche cases where Puppeteer might still be the right choice:
- Screenshots of live websites: If you need to capture actual web pages, you still need a browser
- Complex CSS features: CSS Grid, animations, or advanced features not supported by Satori
- Third-party content: Rendering iframes, embedded widgets, or JavaScript-dependent content
For the vast majority of OG image use cases — text, logos, gradients, and simple layouts — Satori is the better tool.
Try It Yourself
OGPix gives you the power of Satori without writing any code. Design your image in the playground, pick a theme, and get a URL that generates your OG image in ~50ms at the edge.
No Puppeteer. No servers. No headless Chrome. Just fast, beautiful OG images via a simple API call.