Dynamic Social Previews via @nuxt/og-image
OG Images & Schema
nuxt-og-image generates social-preview images at build or runtime using a Vue template — no Puppeteer, no separate service.
What you'll learn
- Install nuxt-og-image
- Define a default OG template
- Override per page with defineOgImageComponent
Hand-rolling OG images means designing 1200x630 PNGs for every blog post. The
nuxt-og-image module renders them from a Vue component instead — at the edge,
on demand.
Install
npx nuxi module add nuxt-og-image The module registers a runtime route at /__og-image__/<path>/og.png. When a
crawler hits that URL, Nuxt renders the matching component to PNG and caches it.
A Default Template
Set a site-wide default in app.vue or any layout — pages without their own OG
image get this one with the page title injected automatically.
<script setup lang="ts">
defineOgImageComponent('NuxtSeo', {
title: 'MySite',
description: 'A great Nuxt site',
theme: '#00DC82',
})
</script> NuxtSeo is a built-in template; you can also point at any component in
components/OgImage/.
Per-Page Override
Inside a blog post, call defineOgImageComponent again with post-specific data:
<script setup lang="ts">
const { data: post } = await useFetch(`/api/posts/${useRoute().params.slug}`)
defineOgImageComponent('NuxtSeo', {
title: post.value!.title,
description: post.value!.excerpt,
icon: 'simple-icons:nuxt',
})
</script> Custom Component
Drop a components/OgImage/MyCard.vue and reference it by name. Use plain HTML
and CSS — the module renders the component to SVG, then to PNG.
<template>
<div class="og">
<h1>{{ title }}</h1>
<p>{{ subtitle }}</p>
</div>
</template>
<script setup lang="ts">
defineProps<{ title: string; subtitle: string }>()
</script>
<style scoped>
.og { width: 1200px; height: 630px; padding: 80px; background: #00DC82; }
</style> Then use it: defineOgImageComponent('MyCard', { title: 'Hi', subtitle: 'World' }).
Build-Time vs Runtime
By default images render on demand. For SSG, the module pre-renders OG images for
every page during nuxi generate — your hosted output ships static PNGs.