Nuxt.js Open Graph Meta Tags: Complete Setup Guide
Add og:title, og:image, og:description, and Twitter card tags to Nuxt 3 apps using useSeoMeta, useHead, and dynamic metadata for blog posts and e-commerce pages.
Why Nuxt 3 is the right choice for OG tags
Nuxt 3 renders pages on the server by default, which means Open Graph meta tags are present in the HTML response before JavaScript runs. Social crawlers (Twitter, LinkedIn, Discord, Slack) never execute JS, so server-rendered OG tags are the only ones that actually work for link previews.
Nuxt 3 ships useSeoMeta — a composable that provides TypeScript-safe OG tag management with zero configuration. It's the recommended approach for all new Nuxt projects.
Basic setup with useSeoMeta
Call useSeoMeta at the top level of any page or layout component:
<!-- pages/index.vue -->
<script setup lang="ts">
useSeoMeta({
title: 'My App — Fast Link Preview Checker',
description: 'Check how your links appear on Twitter, LinkedIn, and Discord.',
ogTitle: 'My App',
ogDescription: 'Check how your links appear on Twitter, LinkedIn, and Discord.',
ogImage: 'https://myapp.com/og/home.jpg',
ogUrl: 'https://myapp.com',
ogType: 'website',
twitterCard: 'summary_large_image',
twitterSite: '@myhandle',
twitterTitle: 'My App',
twitterDescription: 'Check how your links look before you share.',
twitterImage: 'https://myapp.com/og/home.jpg',
})
</script>
<template>
<main><!-- page content --></main>
</template>Dynamic OG tags for blog posts
For content-driven pages where OG data comes from an API, combine useAsyncData with useSeoMeta:
<!-- pages/blog/[slug].vue -->
<script setup lang="ts">
const route = useRoute()
const { data: post } = await useAsyncData(
`post-${route.params.slug}`,
() => $fetch(`/api/posts/${route.params.slug}`)
)
useSeoMeta({
title: () => post.value?.title ?? 'Blog',
ogTitle: () => post.value?.title,
ogDescription: () => post.value?.excerpt,
ogImage: () => post.value?.coverImage,
ogUrl: () => `https://myapp.com/blog/${route.params.slug}`,
ogType: 'article',
twitterCard: 'summary_large_image',
twitterTitle: () => post.value?.title,
twitterImage: () => post.value?.coverImage,
})
</script>Using getter functions (() => value) makes the meta tags reactive — they update automatically when the data loads.
Global defaults in nuxt.config.ts
Set site-wide fallback OG tags in nuxt.config.ts so every page has baseline metadata even if a page-level override is missing:
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
title: 'My App',
meta: [
{ property: 'og:site_name', content: 'My App' },
{ property: 'og:type', content: 'website' },
{ property: 'og:image', content: 'https://myapp.com/og/default.jpg' },
{ name: 'twitter:card', content: 'summary_large_image' },
],
},
},
})
Generating dynamic OG images
Nuxt doesn't have a built-in OG image generator, but you can use nuxt-og-image (community module) or a Vercel Edge Function with @vercel/og to generate unique images per page:
// Install the module
npx nuxi module add nuxt-og-image
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['nuxt-og-image'],
ogImage: {
defaults: {
component: 'OgImageDefault',
},
},
})Common Nuxt OG tag pitfalls
- Missing absolute URLs: all og:image and og:url values must start with
https://. - SPA mode: if you set
ssr: falsein nuxt.config, OG tags won't be server-rendered. Remove it or userouteRulesfor hybrid rendering. - Wrong image dimensions: use 1200×630 px for maximum compatibility.
- Stale platform cache: use each platform's scraping debugger after deploy.
Verify your Nuxt OG tags → Paste your URL into OGFixer to see exactly how your link looks on Twitter, LinkedIn, Discord, and Slack — before you share it.