---
title: "Social Sharing Meta Tags in Vue · Nuxt SEO"
canonical_url: "https://nuxtseo.com/learn-seo/vue/mastering-meta/social-sharing"
last_updated: "2026-07-16T12:00:00.000Z"
meta:
  author: "Harlan Wilton"
  description: "Set Open Graph and Twitter Card tags in Vue so links preview correctly on Facebook, X, LinkedIn, Slack, and Discord instead of plain text."
  "og:description": "Set Open Graph and Twitter Card tags in Vue so links preview correctly on Facebook, X, LinkedIn, Slack, and Discord instead of plain text."
  "og:title": "Social Sharing Meta Tags in Vue · Nuxt SEO"
---

Nuxt SEO on GitHub

# **Social Sharing Meta Tags in Vue**

Set Open Graph and Twitter Card tags in Vue so links preview correctly on Facebook, X, LinkedIn, Slack, and Discord instead of plain text.

[Harlan Wilton](https://x.com/harlan-zw)12 mins read Published **Nov 5, 2024** Updated **Jul 16, 2026**

**What you'll learn**

- OG tags control social previews on Facebook, [**~~LinkedIn~~**](https://linkedin.com), Slack, Discord
- Images must be absolute HTTPS URLs (not relative paths)
- Twitter/X requires `**twitterCard**`: there's no fallback from OG tags

Social platforms use Open Graph (OG) and Twitter Card meta tags to generate link previews. Without them, shared links appear as plain text.

**SSR required**: Social crawlers don't run JavaScript. Your meta tags must be in the initial HTML response, which means [**~~server-side rendering~~**](https://nuxtseo.com/learn-seo/vue/routes-and-rendering/rendering) or prerendering.

```vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  // Open Graph (Facebook, LinkedIn, Discord, Slack)
  ogTitle: 'Your page title',
  ogDescription: 'Short description',
  ogImage: 'https://mysite.com/og.png',
  ogUrl: 'https://mysite.com/page',
  // Twitter/X (required - no OG fallback for card type)
  twitterCard: 'summary_large_image'
})
</script>
```

## Quick Tips

1. **Images matter**: a page with a working `**og:image**` renders as a card with a preview image; a page without one renders as a bare text link. Images must be absolute URLs.
2. **Social titles can differ**: your `**og:title**` doesn't have to match your [**~~page title~~**](https://nuxtseo.com/learn-seo/vue/mastering-meta/titles). Search intent doesn't apply on social, so casual or provocative language works fine.
3. **Always set `**twitterCard**`**: X/Twitter has no fallback for card type. Skip it and you get plain text.

## Open Graph Tags

Use [`**useSeoMeta()**`](https://unhead.unjs.io/docs/head/api/composables/use-seo-meta) for OG tags: it handles the `**property**` attribute automatically.

### Core Tags

```vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  ogTitle: 'Hey! Open graph images are important.',
  ogDescription: 'But who reads the description anyway?',
  ogImage: 'https://mysite.com/og.png', // must be absolute URL
  ogUrl: 'https://mysite.com/products/item', // canonical URL
  ogType: 'website' // or 'article', 'product', etc.
})
</script>
```

### Image Requirements

| **Spec** | **Value** |
| --- | --- |
| Minimum size | 600x315px |
| Recommended size | 1200x600px (2:1) |
| Max file size | 5MB (1MB recommended) |
| Formats | JPG, PNG, WebP, GIF |
| URL | Absolute HTTPS |

Use 1200x600px (2:1): it matches X's card ratio, renders cleanly on Discord and Slack, and Facebook displays it fine even though its own docs still list the older 1.91:1 (1200x630px) spec. One image covers every platform.

Include dimensions for faster rendering:

```vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  ogImage: 'https://mysite.com/og-images/preview.jpg',
  ogImageAlt: 'Product preview showing 3 stacked boxes',
  ogImageWidth: 1200,
  ogImageHeight: 600,
  ogImageType: 'image/jpeg'
})
</script>
```

OG images must use absolute URLs with HTTPS. Relative paths like `**/images/og.png**` won't work: social crawlers don't know your domain. Always include the full URL, such as `**https://mysite.com/images/og.png**`

### Article Metadata

For blog posts, add article-specific tags:

```vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  ogType: 'article',
  articleAuthor: ['Harlan Wilton'],
  articleSection: 'SEO Tutorials',
  articleTag: ['vue', 'seo', 'meta-tags'],
  articlePublishedTime: '2024-11-05T00:00:00Z',
  articleModifiedTime: '2026-07-16T00:00:00Z'
})
</script>
```

## Twitter/X Cards

X requires its own `**twitter:***` meta tags. Without `**twitter:card**`, your links appear as plain text: no image, no description.

### Card Types

**summary\_large\_image**: Full-width image. Use this for most pages.

```vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  twitterCard: 'summary_large_image',
  twitterImage: '/preview.jpg' // 2:1 ratio, min 300x157px
})
</script>
```

**summary**: Small square thumbnail. For compact previews.

```vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  twitterCard: 'summary',
  twitterImage: '/icon.jpg' // 1:1 ratio, min 144x144px
})
</script>
```

**player** and **app** cards require [**~~approval from X~~**](https://developer.x.com/en/docs/x-for-websites/cards/overview/player-card).

### X Fallbacks

X [**~~falls back to Open Graph~~**](https://developer.x.com/en/docs/x-for-websites/cards/overview/markup) when `**twitter:***` equivalents are missing:

| **Twitter Tag** | **Fallback** |
| --- | --- |
| `**twitter:title**` | `**og:title**` |
| `**twitter:description**` | `**og:description**` |
| `**twitter:image**` | `**og:image**` |

`**twitter:card**` has **no fallback**: skip it and you get no card.

Minimal setup using fallbacks:

```vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  twitterCard: 'summary_large_image', // required
  ogTitle: 'My page',
  ogImage: 'https://mysite.com/image.jpg'
})
</script>
```

### Optional Twitter Tags

```vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  twitterSite: '@yourhandle', // Site's X handle
  twitterCreator: '@authorhandle', // Author's handle
  twitterImageAlt: 'Alt text' // 420 chars max
})
</script>
```

## Slack & Discord

Both platforms read Open Graph tags directly, no platform-specific tags needed.

```vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  ogTitle: 'Dashboard Analytics',
  ogDescription: '847 active users, 12.4% conversion rate',
  ogImage: 'https://mysite.com/og/dashboard.png'
})
</script>
```

Slack also reads Twitter Card tags as fallback. Discord supports animated GIFs, but it caches embeds per message rather than fetching live on every view.

Slack-specific behavior:

- Cache: about 30 minutes per URL
- To refresh: add `**?v=2**` to the URL
- Ignores: `**og:type**`, `**og:locale**`, `**article:***` tags, [**~~Schema.org~~**](http://Schema.org)
- No redirect following for images: use direct URLs

## Platform Cache Times

| **Platform** | **Cache Duration** | **Clear Cache** |
| --- | --- | --- |
| Facebook | \~30 days | [**~~Sharing Debugger~~**](https://developers.facebook.com/tools/debug/) |
| LinkedIn | \~7 days | [**~~Post Inspector~~**](https://www.linkedin.com/post-inspector/) |
| X/Twitter | \~7 days (not officially documented) | Add `**?v=2**` to the URL |
| Slack | \~30 minutes | Add `**?v=2**` to the URL |
| Discord | Cached per message | Delete and re-paste the link |
| Telegram | Effectively indefinite | [**~~@WebpageBot~~**](https://t.me/WebpageBot) |

Telegram's OG cache is effectively infinite. While it may expire for links no one has interacted with in a long time, you should assume it never clears on its own. The official [**~~@WebpageBot~~**](https://t.me/WebpageBot) can instantly refresh the OG image and metadata for everyone.

## Dynamic Meta Tags

Data must be available during server render. `**onMounted**` runs too late for crawlers.

```ts
// entry-server.ts
export async function render(url: string) {
  const product = await fetch(`https://api.mysite.com/product/${url}`).then(r => r.json())
  const app = createSSRApp(App)
  app.provide('product', product)
  return { app, product }
}
```

```vue
<script setup lang="ts">
import { useSeoMeta } from '@unhead/vue'
import { inject } from 'vue'

const product = inject <Product> ('product')

useSeoMeta({
  ogTitle: product?.name,
  ogDescription: product?.shortPitch,
  ogImage: `https://mysite.com/api/og?title=${encodeURIComponent(product?.name || '')}`,
  twitterCard: 'summary_large_image'
})
</script>
```

## Testing & Troubleshooting

Test previews before you ship:

1. [**~~Facebook Sharing Debugger~~**](https://developers.facebook.com/tools/debug/): Also validates OG tags for Slack
2. [**~~LinkedIn Post Inspector~~**](https://www.linkedin.com/post-inspector/)
3. X/Twitter: Compose a tweet (don't post) to see preview
4. Discord: Paste link for real-time preview

**Image not showing**

- URL must be absolute HTTPS (not relative)
- File under 5MB
- Image returns 200 (not redirect)
- Not blocked by robots.txt

**Wrong title/description**

- Platform cached the old version: add `**?v=2**` to the URL
- For X: check you're setting `**twitterCard**`

**Card not appearing at all**

- Missing `**twitterCard**` for X (no fallback)
- Page requires auth (crawlers can't log in)

## OG Image Tools

Creating OG images manually is tedious:

- [**~~OG Image Playground~~**](https://og-playground.vercel.app/): Design and export with code
- [**~~x-satori~~**](https://github.com/Zhengqbbb/x-satori): Vue SFCs + Tailwind to generate at build time

## Checklist

**Checklist**

- Set `**ogTitle**`, `**ogDescription**`, `**ogImage**`, and `**ogUrl**` with `**useSeoMeta()**` from `**@unhead/vue**`
- Use an absolute HTTPS URL for `**ogImage**`, at least 600x315px
- Set `**twitterCard**` too: there's no OG fallback for the card type itself
- Fetch data before render (not in `**onMounted()**`) so crawlers see it
- Test previews with the Facebook Sharing Debugger, LinkedIn Post Inspector, or the [**~~Social Share Debugger~~**](https://nuxtseo.com/tools/social-share-debugger)

Using Nuxt? [**~~Nuxt SEO~~**](https://nuxtseo.com/docs/nuxt-seo/getting-started/introduction) handles social sharing automatically with the OG Image module. [**~~Learn more about Social Sharing in Nuxt →~~**](https://nuxtseo.com/learn-seo/nuxt/mastering-meta/open-graph)

[**The 2026 SEO Checklist for Nuxt & Vue ** Pre-launch setup, post-launch verification, and ongoing monitoring. Interactive checklist with links to every guide.](https://nuxtseo.com/learn-seo/checklist) [Haven't launched yet? Start with the **Pre-Launch Warmup**](https://nuxtseo.com/learn-seo/pre-launch-warmup)

---

### **Related **

[**Schema.org in Vue**](https://nuxtseo.com/learn-seo/vue/mastering-meta/schema-org)

[**Vue SSR for SEO**](https://nuxtseo.com/learn-seo/vue/routes-and-rendering/rendering)

### **Open Source **

[**unjs/unhead**** Public **](https://github.com/unjs/unhead)

[**Meta Description** Google rewrites most meta descriptions anyway. Set yours with useHead or useSeoMeta in Vue 3, then put the real effort into content that earns the click.](https://nuxtseo.com/learn-seo/vue/mastering-meta/descriptions) [**Schema.org** Add type-safe JSON-LD to a Vue app with @unhead/schema-org's useSchemaOrg, no Nuxt required.](https://nuxtseo.com/learn-seo/vue/mastering-meta/schema-org)

**On this page**

- [Quick Tips](#quick-tips)
- [Open Graph Tags](#open-graph-tags)
- [Twitter/X Cards](#twitterx-cards)
- [Slack & Discord](#slack-discord)
- [Platform Cache Times](#platform-cache-times)
- [Dynamic Meta Tags](#dynamic-meta-tags)
- [Testing & Troubleshooting](#testing-troubleshooting)
- [OG Image Tools](#og-image-tools)
- [Checklist](#checklist)