Skip to content

Dynamic OG Images

Velocity automatically generates OG images for all pages using Satori.

OG images are generated at build time for each page:

/og/[...slug].png
PageOG Image URL
Homepage/og/index.png
About/og/about.png
Blog post/og/blog/my-post.png

The SEO component automatically references these paths:

<!-- You don't need to specify this -->
<meta property="og:image" content="https://yoursite.com/og/about.png" />

Override for specific pages:

<SEO
title="Special Page"
image="/custom-og-image.png"
/>

OG image settings are in src/lib/og.ts:

export const ogConfig = {
width: 1200,
height: 630,
fonts: ['Outfit', 'JetBrains Mono'],
brandColor: '#F94C10',
};

Edit src/pages/og/[...slug].png.ts:

export async function GET({ params }) {
const title = getPageTitle(params.slug);
const svg = await satori(
{
type: 'div',
props: {
children: [
// Your template JSX
{ type: 'h1', props: { children: title } },
],
style: {
// Styles
},
},
},
{
width: 1200,
height: 630,
fonts: await loadFonts(),
}
);
return new Response(svgToPng(svg), {
headers: { 'Content-Type': 'image/png' },
});
}
  1. Check that dimensions are valid (1200x630 recommended)
  2. Ensure fonts are available
  3. Check build logs for errors

Fonts must be loaded as ArrayBuffers:

const fontData = await fetch(fontUrl).then(r => r.arrayBuffer());

OG generation can be slow for large sites. Consider:

  • Caching generated images
  • Using simpler templates
  • Reducing font complexity