The Puppeteer approach breaks down fast once you need OG images at any real scale — cold start alone can add 2-3 seconds on a serverless function, and the memory footprint makes horizontal scaling expensive.
I had to solve a version of this for a financial data site with 8,000+ stock and ETF pages, each needing its own branded OG image with ticker, company name, and a price sparkline. Puppeteer was the obvious first instinct but the idea of spinning up a headless browser per request was a non-starter. We ended up pre-generating images at deploy time using a Node.js + canvas pipeline and serving them as static assets from CDN — solves the latency problem entirely but means you're regenerating on every deploy rather than on-demand.
The on-demand API approach you've built is the right answer for dynamic content where you can't pre-generate. Curious about your caching layer — are you storing generated images at the CDN edge keyed by parameters, or regenerating on every request? For something serving social sharing previews, a long-lived edge cache probably gets your effective p99 well below 50ms for any URL that's been shared before.
Great question! Yes, images are CDN cached at the edge keyed by the full query string. Same params = instant cache hit (~5ms). TTL is 24h via s-maxage=86400.
Your pre-gen approach is smart for 8K+ known pages. On-demand API shines for dynamic content you can't predict at build time.
I chose Satori over canvas for more consistent text rendering across environments — React JSX → SVG → PNG, no browser needed.
Really appreciate the detail here — the s-maxage=86400 CDN caching strategy is clever. For my use case (8K+ stock ticker pages with OG images), I went the pre-gen route since the tickers are known ahead of time. But your point about on-demand for dynamic content makes a lot of sense.
Satori is interesting — I hadn't considered the React JSX → SVG → PNG pipeline. Does the SVG intermediate step add any noticeable latency compared to going straight to canvas? Curious if you've benchmarked that path.
The SVG step barely matters. Satori does JSX to SVG in about 10-15ms, resvg turns that into PNG in another 20-30ms. Under 50ms total. Raw canvas might be a few ms faster but I never benchmarked them against each other because it wouldn't change the architecture either way.
I picked Satori over canvas because writing layout in canvas coordinates is painful. You end up calculating x/y for every text element, handling word wrap manually, messing with font metrics. It works, but it's a lot of tedious code. Satori lets you write a React component with flexbox and it figures out positioning for you. Much less to maintain.
For your ticker pages, pre-gen at deploy time makes total sense since you already know every page upfront. On-demand is better when you can't predict what pages will exist, like user generated content or search results. And once the CDN caches a response, only the very first request actually generates anything. After that it's just serving a static file.
Really helpful breakdown on the Satori vs canvas tradeoff — the flexbox layout abstraction is exactly what makes it maintainable at scale. We went the pre-gen route for our 8K+ ticker pages and the build-time cost is negligible since it's just one more step in the Astro build pipeline.
The CDN caching point is key too. Once an OG image is generated and cached, it's essentially free. The only tricky part for us is invalidation — when stock data updates daily, we need the OG images to reflect current prices without regenerating everything. Still figuring out the right balance there.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
The Puppeteer approach breaks down fast once you need OG images at any real scale — cold start alone can add 2-3 seconds on a serverless function, and the memory footprint makes horizontal scaling expensive.
I had to solve a version of this for a financial data site with 8,000+ stock and ETF pages, each needing its own branded OG image with ticker, company name, and a price sparkline. Puppeteer was the obvious first instinct but the idea of spinning up a headless browser per request was a non-starter. We ended up pre-generating images at deploy time using a Node.js + canvas pipeline and serving them as static assets from CDN — solves the latency problem entirely but means you're regenerating on every deploy rather than on-demand.
The on-demand API approach you've built is the right answer for dynamic content where you can't pre-generate. Curious about your caching layer — are you storing generated images at the CDN edge keyed by parameters, or regenerating on every request? For something serving social sharing previews, a long-lived edge cache probably gets your effective p99 well below 50ms for any URL that's been shared before.
Great question! Yes, images are CDN cached at the edge keyed by the full query string. Same params = instant cache hit (~5ms). TTL is 24h via s-maxage=86400.
Your pre-gen approach is smart for 8K+ known pages. On-demand API shines for dynamic content you can't predict at build time.
I chose Satori over canvas for more consistent text rendering across environments — React JSX → SVG → PNG, no browser needed.
Really appreciate the detail here — the s-maxage=86400 CDN caching strategy is clever. For my use case (8K+ stock ticker pages with OG images), I went the pre-gen route since the tickers are known ahead of time. But your point about on-demand for dynamic content makes a lot of sense.
Satori is interesting — I hadn't considered the React JSX → SVG → PNG pipeline. Does the SVG intermediate step add any noticeable latency compared to going straight to canvas? Curious if you've benchmarked that path.
The SVG step barely matters. Satori does JSX to SVG in about 10-15ms, resvg turns that into PNG in another 20-30ms. Under 50ms total. Raw canvas might be a few ms faster but I never benchmarked them against each other because it wouldn't change the architecture either way.
I picked Satori over canvas because writing layout in canvas coordinates is painful. You end up calculating x/y for every text element, handling word wrap manually, messing with font metrics. It works, but it's a lot of tedious code. Satori lets you write a React component with flexbox and it figures out positioning for you. Much less to maintain.
For your ticker pages, pre-gen at deploy time makes total sense since you already know every page upfront. On-demand is better when you can't predict what pages will exist, like user generated content or search results. And once the CDN caches a response, only the very first request actually generates anything. After that it's just serving a static file.
Really helpful breakdown on the Satori vs canvas tradeoff — the flexbox layout abstraction is exactly what makes it maintainable at scale. We went the pre-gen route for our 8K+ ticker pages and the build-time cost is negligible since it's just one more step in the Astro build pipeline.
The CDN caching point is key too. Once an OG image is generated and cached, it's essentially free. The only tricky part for us is invalidation — when stock data updates daily, we need the OG images to reflect current prices without regenerating everything. Still figuring out the right balance there.