A recent post on the HTML to Image blog looked at why @vercel/og drops emoji from your Open Graph images. That is not a one-off bug. It is a symptom of how the whole thing works. The engine underneath @vercel/og and next/og is Satori, and Satori is not a browser. It converts HTML and CSS into SVG using a flexbox layout engine, and it implements a deliberately small subset of CSS. Emoji is one thing that subset leaves out. This post covers the rest, so you know why a card that looks right in Chrome can break, or quietly render wrong, the moment Satori touches it. Satori is not a browser Satori uses the same flexbox layout engine as React Native, the Yoga engine, and it is clear in its own docs that this is not a complete CSS implementation. @vercel/og wraps it: Satori produces the SVG, then it is rasterised to PNG, the whole thing designed to run in an edge function. You can read the supported list in the Satori readme and Vercel's OG image docs . The mental model that saves you time is this. You are not writing CSS for a browser. You are writing for Yoga plus a curated set of properties. Almost every surprise comes from assuming browser behaviour that Satori never promised. Everything is flexbox The headline limit is layout. In Satori, display is either flex or none . There is no block , no inline-block , no table and, the one that catches most people, no grid . Vercel's docs say it plainly: advanced layouts using display: grid will not work. Because the default is flex and there is no block flow, any element with more than one child has to declare its display explicitly. Leave it out and you get the error every Satori user has seen: import { ImageResponse } from ' @vercel/og ' new ImageResponse ( < div style = { { color : ' white ' } } > < h1 > Title </ h1 > < p > Subtitle </ p > </ div > ) // Error: Expected
<div style="display:grid; grid-template-columns:1fr 1fr; gap:24px;"> <div>Grid works here</div> <div>So do ::before and web fonts</div> </div> , width : 1200 , height : 630 , }), }) const { url } = await res . json () If you are weighing the two for a Next.js project, the walk-through on dynamic OG images in Next.js without @vercel/og sets the API approach next to the Satori one. The Open Graph image template is a ready starting point, and there is a no-code Open Graph image generator if you want to design a card without writing the markup first. Outgrowing Satori's CSS subset and want OG cards rendered in a full browser engine? Browse the templates gallery or read the docs to get started.

