ScreenshotNeo

BlogHow-to

How to Add Open Graph Tags to a Nuxt Website

Add shared and page-specific Open Graph tags in Nuxt 4 with useSeoMeta, verify the rendered head, and fix common preview problems.

By the ScreenshotNeo team4 October 20267 min read

In Nuxt 4, use useSeoMeta() to define Open Graph metadata. Put site-wide defaults in app/app.vue, then set or override values in the page that knows its own content. Make sure every page has og:title, og:type, og:image, and og:url; add a concise description and image alt text as well.

Nuxt recommends useSeoMeta() for SEO metadata: it provides typed fields and helps avoid mistakes such as using a name attribute where a property attribute is needed. The examples below target Nuxt 4. Nuxt 3 reached end of life on 31 July 2026, so use the version-specific documentation if maintaining a Nuxt 3 application. Nuxt SEO and Meta guide · useSeoMeta API · Nuxt 3 SEO guide.

1. Know which tags to add

The Open Graph Protocol defines four required properties for a page:

Open Graph property Nuxt field What to provide
og:title ogTitle A clear title for the page or content.
og:type ogType The kind of object, such as website or article.
og:image ogImage An absolute URL to a publicly accessible preview image.
og:url ogUrl The canonical URL that identifies this page.

og:description is optional in the protocol and usually useful for a preview. Add og:image:alt to describe the image when you provide an image; the protocol specifies that the alt value should describe the image rather than act as a caption. Nuxt exposes these as ogDescription and ogImageAlt. See the Open Graph Protocol.

Use absolute HTTPS URLs for the canonical page and image. The canonical URL should identify the page represented by the metadata, and the image must be reachable by the service fetching the page. Nuxt’s example uses an absolute HTTPS image URL. This guidance does not imply that every social platform has identical crawler, cache, authentication, or image-size requirements.

2. Add shared defaults in Nuxt 4

For metadata shared by the application, add defaults in app/app.vue:

<!-- app/app.vue -->
<script setup lang="ts">
useSeoMeta({
  ogSiteName: 'Example Site',
  ogType: 'website',
  ogTitle: 'Example Site',
  ogDescription: 'A short description of this website.',
  ogUrl: 'https://example.com/',
  ogImage: 'https://example.com/social-card.jpg',
  ogImageAlt: 'Example Site homepage preview',
})
</script>

<template>
  <NuxtPage />
</template>

Replace the example domain, description, and image with real values for your site. Global defaults are a fallback: define page-specific values on pages where the title, description, canonical URL, or image differs.

3. Set metadata for each page

For a fixed page, set its values directly in that page component. For a dynamic route, derive them from the data loaded for the current route. This example assumes the project already has a data-loading function; loadArticleForCurrentRoute() is illustrative pseudocode, not a Nuxt API.

<!-- app/pages/articles/[slug].vue -->
<script setup lang="ts">
const article = await loadArticleForCurrentRoute()

useSeoMeta({
  ogType: 'article',
  ogTitle: () => article.value.title,
  ogDescription: () => article.value.summary,
  ogUrl: () => `https://example.com/articles/${article.value.slug}`,
  ogImage: () => article.value.socialImage,
  ogImageAlt: () => article.value.socialImageAlt,
})
</script>

<template>
  <article>
    <h1>{{ article.title }}</h1>
    <p>{{ article.summary }}</p>
  </article>
</template>

Use your actual content source in place of the illustrative function. Ensure that it returns a title, description, canonical slug, and absolute public image URL before the page metadata is needed. If values can change reactively, the getter form shown above lets Nuxt read their current values. Avoid deriving the canonical URL from an untrusted or arbitrary request host; use your site’s canonical origin.

4. Choose between useSeoMeta, useHead, and app.head

Approach Use it when Example shape
useSeoMeta() You are setting common SEO or Open Graph fields and want the typed, semantic API Nuxt recommends. useSeoMeta({ ogTitle: 'Page title' })
useHead() You need lower-level control over head entries or need to construct metadata dynamically. useHead({ meta: [{ property: 'og:title', content: 'Page title' }] })
app.head in nuxt.config.ts You need static application-wide head defaults that do not depend on route or reactive data. Static metadata in the Nuxt configuration.

Here is the lower-level useHead() shape for Open Graph tags:

<script setup lang="ts">
useHead({
  meta: [
    { property: 'og:title', content: 'Example page' },
    { property: 'og:type', content: 'website' },
    { property: 'og:url', content: 'https://example.com/page' },
    { property: 'og:image', content: 'https://example.com/page-card.jpg' },
    { property: 'og:image:alt', content: 'Illustration for the example page' },
    { property: 'og:description', content: 'A concise page description.' },
  ],
})
</script>

Use property for Open Graph entries with useHead(). useSeoMeta() handles the right metadata attributes through its typed fields. The Nuxt guide describes app.head as suitable for static defaults; for reactive data, use a composable in the app or page context.

5. Verify the rendered document

  1. Run the Nuxt app and open the target route.
  2. Inspect the rendered document head, including the HTML returned by the server for the route. Confirm there is one effective value for each required Open Graph property.
  3. Check that the title and description match the page, the canonical URL is the intended permanent page URL, and the image URL is absolute and publicly reachable.
  4. When a preview is missing or stale, inspect the rendered head first. If the values are correct but a particular platform still shows an old preview, consult that platform’s current crawler and cache guidance; crawler behavior is outside Nuxt’s metadata configuration.

This verification checklist follows from the protocol’s required properties and Nuxt’s head-management behavior; it is not a guarantee about any specific social platform’s fetching or caching.

6. Troubleshoot common problems

Symptom Likely cause Fix
The preview has no title, image, or link target. A required Open Graph property is absent or has an empty value in the rendered head. Inspect the target route’s rendered HTML and add or correct og:title, og:type, og:image, and og:url.
Every route shows the same title or image. Only global defaults are set, or the page’s values are not derived from the current content. Set route-specific metadata in the page component and verify its data is loaded before the getters read it.
The image does not load in a preview. The value may be relative, inaccessible to the fetching service, or not the intended image URL. Use an absolute HTTPS URL to an image that can be fetched publicly; inspect the exact URL emitted in the head.
Nuxt reports an unknown metadata field or the tag is malformed. A field name or head entry shape may be incorrect. Use the documented camel-case useSeoMeta() field (for example, ogTitle) or the property/content form with useHead().
Reactive route data appears outdated. The metadata may have been assigned a one-time value instead of a reactive getter, or the data source has not updated for the route. Use getter syntax for reactive values and confirm the page data reflects the current route before building its canonical URL and image value.
The source looks correct, but a preview remains old. The HTML may differ from what the crawler receives, or the platform may retain a cached preview. Check the server-rendered response and the exact URL used for the preview. Then use the platform’s current preview debugging or cache refresh process.

7. Performance, reliability, and cost

Metadata itself is small; the main reliability concern is having correct values available when the page head is rendered. For dynamic routes, load the page record through the application’s normal data source and provide stable fallbacks or a deliberate not-found response if the record is missing. Keep canonical URLs deterministic, and avoid making social metadata depend on browser-only state that is unavailable during server rendering.

Open Graph metadata does not require a screenshot service. If you need a custom social card for each page, provide a stable image URL in ogImage; this dossier does not establish a universal image-size rule, a crawler cache duration, or a platform-specific rendering guarantee. Nuxt configuration and the composables described here have no per-capture charge. If you choose to generate screenshot assets through an API, account for that service’s plan and usage terms separately.

Or skip the browser setup

If you need a page screenshot as a social card or another preview asset, ScreenshotNeo provides a website screenshot API and MCP server for developers. One GET request can return an image or PDF. The API can also apply custom CSS and JavaScript, choose a viewport, and wait for a page condition; see the ScreenshotNeo documentation for options.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
const image = Buffer.from(await res.arrayBuffer());
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', image));

Replace the example URL with the page you want to capture and keep the access key private. ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Learn about ScreenshotNeo, then sign up for 1,000 free screenshots a month with no card.

FAQ

Should every Nuxt route have its own Open Graph image?

Use a route-specific image when each route represents distinct content and has an appropriate image. Shared defaults are useful for pages that do not provide their own values.

Is og:image:alt required?

The protocol recommends specifying it whenever a page specifies og:image. Describe the image’s content rather than writing a caption.

Can I put dynamic Open Graph tags in nuxt.config.ts?

app.head is for static defaults. Put route-aware or reactive values in useSeoMeta() or useHead() in the app or page context.