
Description
Expert guidance for Satori — Vercel's library that converts HTML and CSS to SVG, commonly used to generate dynamic OG images for Next.js and other frameworks.
SKILL.md
Satori — HTML/CSS to SVG for OG Images
You are an expert in Satori and @vercel/og for generating dynamic Open Graph images.
Overview
Satori converts JSX-like HTML and CSS into SVG. @vercel/og wraps Satori with an ImageResponse class that renders the SVG to PNG, designed to run in Vercel Edge Functions and other edge runtimes.
Installation
# For Next.js projects (recommended — includes Satori + PNG rendering)
npm install @vercel/og
# Standalone Satori (SVG output only)
npm install satori
Next.js App Router — OG Image Route (Recommended)
Next.js has built-in OG image support via the ImageResponse re-exported from next/og:
// app/og/route.tsx OR app/opengraph-image.tsx
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
export async function GET(request: Request) {
return new ImageResponse(
(
<div
style={{
display: 'flex',
fontSize: 60,
color: 'white',
background: 'linear-gradient(to bottom, #1a1a2e, #16213e)',
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
}}
>
Hello, OG Image!
</div>
),
{ width: 1200, height: 630 }
)
}
Convention-Based OG Images (Next.js 13.3+)
Place an opengraph-image.tsx or twitter-image.tsx file in any route segment:
// app/blog/[slug]/opengraph-image.tsx
import { ImageResponse } from 'next/og'
export const alt = 'Blog post image'
export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'
export const runtime = 'edge'
export default async function Image({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
return new ImageResponse(
(
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
height: '100%',
background: '#000',
color: '#fff',
fontSize: 48,
}}
>
<div>{post.title}</div>
</div>
),
{ ...size }
)
}
Next.js auto-generates the <meta property="og:image"> tag for these files.
Standalone Satori (SVG Only)
import satori from 'satori'
import { readFileSync } from 'fs'
const svg = await satori(
<div style={{ display: 'flex', color: 'black', fontSize: 40 }}>
Hello from Satori
</div>,
{
width: 1200,
height: 630,
fonts: [
{
name: 'Inter',
data: readFileSync('./fonts/Inter-Regular.ttf'),
weight: 400,
style: 'normal',
},
],
}
)
CSS Support and Limitations
Satori uses a subset of CSS with Flexbox layout (Yoga engine):
Supported:
display: flex(default — all elements are flex containers)- Flexbox properties:
flexDirection,alignItems,justifyContent,flexWrap,gap - Box model:
width,height,padding,margin,border,borderRadius - Typography:
fontSize,fontWeight,fontFamily,lineHeight,letterSpacing,textAlign - Colors:
color,background,backgroundColor,opacity - Backgrounds:
backgroundImage(linear/radial gradients),backgroundClip - Shadows:
boxShadow,textShadow - Transforms:
transform(basic transforms) - Overflow:
overflow: hidden - Position:
absolute,relative - White space:
whiteSpace,wordBreak,textOverflow
Not supported:
display: grid— use nested flex containers instead- CSS animations or transitions
position: fixedorsticky- Pseudo-elements (
::before,::after) - Media queries
- CSS variables
Fonts
Fonts must be loaded explicitly — there are no default system fonts:
// Load font in edge runtime
const font = fetch(new URL('./Inter-Bold.ttf', import.meta.url)).then(
(res) => res.arrayBuffer()
)
export async function GET() {
const fontData = await font
return new ImageResponse(
(<div style={{ fontFamily: 'Inter' }}>Hello</div>),
{
width: 1200,
height: 630,
fonts: [{ name: 'Inter', data: fontData, weight: 700, style: 'normal' }],
}
)
}
For Google Fonts, fetch directly from the CDN or bundle the .ttf file.
Dynamic Content from URL Parameters
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const title = searchParams.get('title') ?? 'Default Title'
return new ImageResponse(
(<div style={{ display: 'flex', fontSize: 60 }}>{title}</div>),
{ width: 1200, height: 630 }
)
}
Images in OG
Use <img> with absolute URLs:
<img
src="https://example.com/avatar.png"
width={100}
height={100}
style={{ borderRadius: '50%' }}
/>
For local images, convert to base64 or use absolute deployment URLs.
Key Patterns
- Use
next/ogin Next.js projects — it re-exportsImageResponsewith built-in optimizations - Always set
runtime = 'edge'— Satori and@vercel/ogare designed for edge runtimes - Use
display: 'flex'everywhere — Satori defaults to flex layout, no block or grid support - Load fonts explicitly — no system fonts are available; bundle
.ttf/.wofffiles or fetch from CDN - Standard OG dimensions are 1200×630 — this is the most widely supported size
- Use convention files for automatic
<meta>tags —opengraph-image.tsxandtwitter-image.tsx - Inline styles only — Satori does not support external CSS or CSS-in-JS libraries
Official Resources
More skills from the plugins repository
View all 600 skillsaccessibility-and-inclusive-visualization
make data visualizations accessible
Jun 30AccessibilityChartsData VisualizationDesignagent-browser
automate browser interactions for agents
Apr 6AgentsBrowser AutomationTestingagent-browser-verify
verify dev server output with automated browser
Apr 6Browser AutomationLocal DevelopmentTestingagents-sdk
build AI agents on Cloudflare Workers
Apr 6AgentsCloudflare WorkersSDKServerless +1ai-elements
build chat UIs with AI Elements
Apr 6FrontendReactshadcn/uiUI Components +1ai-gateway
configure Vercel AI Gateway
Apr 6AI InfrastructureCost OptimizationLLMPerformance +1
More from OpenAI
View publisherprior-auth-packet-builder
build healthcare prior authorization packets
openai-agents-python
Apr 16DocumentsHealthcareInsuranceRegulatory Complianceaspnet-core
build ASP.NET Core web applications
skills
Apr 12.NETASP.NET CoreBlazorC# +1chatgpt-apps
build ChatGPT Apps SDK applications
skills
Apr 12Apps SDKChatGPTMCPOpenAIcli-creator
build CLIs from API docs
skills
Apr 12API DevelopmentCLICodexcloudflare-deploy
deploy projects to Cloudflare
skills
Apr 12CloudflareCloudflare PagesCloudflare WorkersDeploymentdefine-goal
define and set measurable project goals
skills
May 23ProductivityProject ManagementStrategyTask Management