Mastering Open Graph Tags in Vue & Nuxt
Introduction
Open Graph (OG) tags mainly control how your content appears when shared on social platforms. However, they can also provide better content understanding for web crawlers, similar to Schema.org.
There are 60+ possible OG tags but most have specific use cases.
<meta property="og:title" content="Your title that matters">
<meta property="og:description" content="Short description">
<meta property="og:image" content="https://mysite.com/og.png">
<meta property="og:url" content="https://mysite.com/page">
Quick Tips
- Images matter: A good og:image can double your click-through rate, they must be an absolute URL and at least 1200x600px.
- Make the title engaging: Your og:title doesn't have to match your page title. While page titles need to be SEO-friendly, your og:title can be casual and provocative. Use emojis, numbers, and conversational language - social isn't search.
- Leverage Contextual OG Types: You can mark up articles and author pages to provide more context for crawlers.
Implementation in Vue
You should handle your OG tags with useSeoMeta()
,
this handles the use property
attribute, which can be easy to forget.
useSeoMeta({
ogTitle: 'Hey! Open graph images are important, check them out.',
ogDescription: 'But who reads the description anyway?',
ogImage: 'https://mysite.com/og.png', // must be absolute URL
ogUrl: 'https://mysite.com/products/item' // this is your canonical url
})
Useful Open Graph Tags
See the dedicated og:title
and og:description
sections for more details on these.
og:image
The most important tag - invest time here.
Some rules:
- Must be an absolute URL
- Should be at least 1200x600px
- Set a
twitter:card
tag for X - Use
og:image:alt
for accessibility
There are several other properties, including them can be useful to ensure the image is being displayed correctly.
useSeoMeta({
// ✅ use absolute URLs
ogImage: 'https://mysite.com/og-images/product-preview.jpg',
ogImageAlt: '3 boxes on top of each other',
// Optional
ogImageWidth: 1200,
ogImageHeight: 600,
ogImageType: 'image/jpeg',
ogImageUrl: 'https://mysite.com/og-images/product-preview.jpg',
// X specific tags
twitterCard: 'summary_large_image',
twitterImage: 'https://mysite.com/og-images/product-preview.jpg',
twitterImageSrc: 'https://mysite.com/og-images/product-preview.jpg'
})
Create dynamic images using Nuxt OG Image.
og:type
{lang="ts}
Use this to provide context to crawlers. Common values are website
, article
, book
, profile
.
useSeoMeta({
ogType: 'article'
})
og:url
{lang="ts}
Use this when setting your canonical URL, they should match exactly.
useHead({
link: [
{ rel: 'canonical', href: 'https://mysite.com/products/item' }
]
})
useSeoMeta({
ogUrl: 'https://mysite.com/products/item',
})
Dynamic OG Tags
Use Vue's reactivity to handle dynamic content.
- Do not set
og
data withinonMounted
as it won't be available to crawlers.
<script setup lang="ts">
const { data: product } = await useAsyncData(() => fetchProduct())
useSeoMeta({
// Computed syntax keeps it reactive
ogTitle: () => product.value.name,
ogDescription: () => product.value.shortPitch,
// Generate dynamic OG images - must be absolute
ogImage: () => `https://mysite.com/api/og?title=${product.value.name}`
})
</script>
Platform Specific Notes
- Uses their own crawler
- Cache time: ~30 days
- Force refresh: Use Sharing Debugger
- Aggressive caching (7+ days)
- Images must be public (no auth)
- Clear cache: Post Inspector
Discord
- Real-time preview
- Supports animated GIFs
- No cache clearing needed
Twitter (X)
- Prefers Twitter Cards
- Only uses og:image from OG tags
- Test with Card Validator
Testing & Verification
Always test your OG tags:
- Use the Facebook Sharing Debugger
- Check LinkedIn Post Inspector
- Share in Discord (real-time preview)
Common Patterns
Blog Posts
useSeoMeta({
ogType: 'article',
author: 'Harlan Wilton',
// open graph
articleAuthor: ['Harlan Wilton'],
articleSection: 'SEO Tutorials for Vue and Nuxt',
articleTag: page.value.keywords,
articlePublishedTime,
articleModifiedTime,
// slack unfurling
twitterData1: 'Harlan Wilton',
twitterLabel1: 'Author',
twitterData2: page.value.readTime,
twitterLabel2: 'Read Time',
})
Meta Description
Meta descriptions get rewritten by Google 70% of the time anyway. Here's how to implement them properly in Vue using composables and let your content do the heavy lifting.
Schema.org
Schema.org can help search engines understand your content better, but is it worth the effort? Learn when to use it and when to skip it in Vue & Nuxt applications.