---
title: "Twitter Cards in Nuxt"
description: "Configure Twitter/X Cards to control how your links appear when shared on Twitter with rich previews, images, and metadata."
canonical_url: "https://nuxtseo.com/learn-seo/nuxt/mastering-meta/twitter-cards"
last_updated: "2024-12-05"
---

<key-takeaways>

- Twitter requires `twitterCard`; OG tags won't fallback for card type
- Use `summary_large_image` for full-width previews (1200x600px recommended)
- Twitter falls back to OG for title/description, but not for the card type itself

</key-takeaways>

Twitter/X falls back to [Open Graph tags](/learn-seo/nuxt/mastering-meta/open-graph) for title, description, and image. Set up OG tags first, then add Twitter-specific overrides described below.

Twitter requires its own `twitter:card` meta tag for rich link previews. Without it, your links appear as plain text with no image or description.

```vue
<script setup lang="ts">
useSeoMeta({
  twitterCard: 'summary_large_image',
  twitterImage: '/social-preview.jpg',
  twitterTitle: 'Your page title',
  twitterDescription: 'Your page description'
})
</script>
```

## Card Types

Twitter supports four card types via `twitter:card`:

**summary_large_image** - Full-width image preview (1200x600px). Use this for most pages.

```vue
useSeoMeta({
  twitterCard: 'summary_large_image',
  twitterImage: '/preview.jpg' // Minimum 300x157px, aspect ratio 2:1
})
```

**summary** - Small square thumbnail (1:1 aspect ratio). Don't use this unless you specifically want a smaller preview.

```vue
useSeoMeta({
  twitterCard: 'summary',
  twitterImage: '/icon.jpg' // Minimum 144x144px
})
```

**player** - Embedded video/audio player. Requires approval from Twitter.

**app** - Mobile app install prompts. Requires app store URLs and IDs.

Most sites should only use `summary_large_image`.

## Required Tags

These three tags are mandatory for any Twitter Card:

```vue
useSeoMeta({
  twitterCard: 'summary_large_image',
  twitterTitle: 'Page title - 70 characters max',
  twitterImage: 'https://example.com/image.jpg' // Must be absolute URL
})
```

Image requirements match [Open Graph specs](/learn-seo/nuxt/mastering-meta/open-graph#image-requirements). The exception: `summary_large_image` uses a 2:1 ratio instead of OG's 1.91:1.

## Optional Tags

```vue
useSeoMeta({
  twitterCard: 'summary_large_image',
  twitterTitle: 'Your title',
  twitterImage: '/preview.jpg',
  twitterDescription: 'Description text - 200 characters max',
  twitterSite: '@yourhandle', // Your site's Twitter handle
  twitterCreator: '@authorhandle' // Content author's handle
})
```

`twitterDescription` defaults to `og:description` if not set, but specify it to control the exact text Twitter shows.

## Open Graph Fallbacks

Twitter falls back to Open Graph tags when `twitter:*` tags are missing:

<table>
<thead>
  <tr>
    <th>
      Twitter Tag
    </th>
    
    <th>
      Fallback
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        twitter:title
      </code>
    </td>
    
    <td>
      <code>
        og:title
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        twitter:description
      </code>
    </td>
    
    <td>
      <code>
        og:description
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        twitter:image
      </code>
    </td>
    
    <td>
      <code>
        og:image
      </code>
    </td>
  </tr>
</tbody>
</table>

This won't work:

```vue
// ❌ Twitter will show nothing
useSeoMeta({
  ogTitle: 'My page',
  ogImage: '/image.jpg'
})
```

This works:

```vue
// ✅ Twitter uses og:* tags as fallback
useSeoMeta({
  twitterCard: 'summary_large_image', // Required - no fallback
  ogTitle: 'My page',
  ogImage: '/image.jpg'
})
```

Set both to avoid relying on fallback behavior:

```vue
// ✅ Explicit control
useSeoMeta({
  twitterCard: 'summary_large_image',
  twitterTitle: 'Twitter-specific title (70 chars)',
  twitterImage: '/twitter-preview.jpg',
  ogTitle: 'OpenGraph title can be longer',
  ogImage: '/og-preview.jpg'
})
```

## Testing

Use our [Social Share Debugger](/tools/social-share-debugger) to preview how your links appear on Twitter, Facebook, [LinkedIn](https://linkedin.com), and other platforms.

You can also use [Twitter Card Validator](https://cards-dev.twitter.com/validator) directly.

The validator caches results. If you update tags and don't see changes:

1. Add a query parameter: `?v=2`
2. Wait 7 days for cache to expire
3. Use a different URL to test

Common issues:

**Image not showing** - Check that:

- URL is absolute with HTTPS
- File size is under 5MB
- Image exists and returns 200 status
- No robots.txt blocking Twitter's bot

**Wrong title/description** - Twitter cached the old version. Add `?v=1` to the URL.

**Card not appearing** - You forgot `twitterCard` meta tag. It has no fallback.

## Per-Page Cards

Set different cards for different pages:

```vue
<!-- ~/pages/blog/[slug].vue -->
<script setup lang="ts">
const { data: post } = await useAsyncData('post', () =>
  queryContent('blog', route.params.slug).findOne())

useSeoMeta({
  twitterCard: 'summary_large_image',
  twitterTitle: post.value.title,
  twitterDescription: post.value.excerpt,
  twitterImage: post.value.coverImage
})
</script>
```

Works best for blog posts with feature images, product pages with photos, landing pages with marketing visuals. Skip it for internal tools or password-protected content (Twitter can't fetch behind auth anyway).

## Automated OG Image Generation

See [Automated OG Image Generation](/learn-seo/nuxt/mastering-meta/open-graph#automated-og-image-generation) for automatic image creation with the Nuxt OG Image module.
