How to add Open Graph tags to a Vue website
Add Open Graph tags to a Vue site, set different previews per route, and choose client-side, SSR, or static generation based on when your metadata is available.
To add Open Graph tags to a Vue website, put og:title, og:type, og:image, and og:url in the document <head>. Add a useful og:description and descriptive og:image:alt as well. For route-specific previews, keep values with each page or Vue Router route and render the matching tags in the HTML for that URL. If previews must be present in the initial response, use server-side rendering (SSR) or static site generation (SSG).
1. Add the required Open Graph properties
Open Graph properties are HTML meta elements in the document head. The protocol defines four required properties: og:title, og:type, og:image, and og:url. The URL identifies the object; use the page’s permanent, absolute canonical URL. The image should be an absolute URL to an image representing that page. Open Graph Protocol
<head>
<meta property="og:title" content="Example article title">
<meta property="og:type" content="article">
<meta property="og:url" content="https://example.com/articles/example">
<meta property="og:image" content="https://example.com/images/example-preview.jpg">
<meta property="og:description" content="A concise summary of this article.">
<meta property="og:image:alt" content="A description of the article preview image">
</head>
Replace every example value with real page data. The protocol makes og:description optional, but it is generally useful and should summarize the object in one or two sentences. When you supply og:image, the protocol says to provide og:image:alt describing the image. Alt text describes what is in the image; it is not a caption.
Optional image properties
Open Graph also defines structured image properties: og:image:secure_url, og:image:type, og:image:width, og:image:height, and og:image:alt. Include dimensions and MIME type when you know the correct values and they are useful to your implementation. The protocol does not establish one universal preview-image dimension, so do not treat a particular size as an Open Graph requirement. See the protocol’s image properties.
2. Choose how Vue will render the tags
The right implementation depends on whether every page shares the same metadata, whether the values vary by URL, and when the page data becomes available.
| Approach | Good fit | What to verify |
|---|---|---|
| Static tags in the shared HTML template | One set of values is appropriate for every URL, or previews are not route-specific. | The template is the actual HTML document served by the app, and the values are accurate for all URLs using it. |
| Client-side route updates | Metadata varies by route and can be updated when the Vue app runs in the browser. | Inspect the rendered page and the initial HTML response. Do not assume a sharing service executes client-side code. |
| SSR | Metadata depends on request-time or asynchronously fetched page data and should be included in server-rendered HTML. | The server renders the correct tags for the requested URL and data. |
| SSG or prerendering | Page content and metadata are known at build time and can be generated as static HTML. | Each generated URL has its own correct head values. |
Vue describes SSR as rendering the application into HTML strings on the server and notes it may be needed when asynchronously fetched content matters for SEO. SSG generates static HTML ahead of time and suits content that does not vary between requests. Vue’s quick-start recommends a framework when SSR is needed; for a simpler project that does not need SSR, it describes Vite as a simpler setup. Vue SSR guide · Vue quick start.
3. Set page-specific tags with Vue Router
Vue Router route records accept arbitrary metadata. The matched route exposes route.meta, a non-recursive merge of parent and child route metadata. Use your own property names to store page values, then translate them into Open Graph properties through the head-management approach used by your app. The names ogTitle and ogDescription below are application conventions; Vue Router does not turn them into HTML tags automatically. Vue Router route meta fields.
const routes = [
{
path: '/articles/example',
component: ArticlePage,
meta: {
ogTitle: 'Example article title',
ogDescription: 'A concise summary of this article.',
ogImage: 'https://example.com/images/example-preview.jpg',
ogType: 'article',
canonicalUrl: 'https://example.com/articles/example',
ogImageAlt: 'A description of the article preview image',
},
},
]
// In a component or route-aware head integration:
const route = useRoute()
const preview = {
title: route.meta.ogTitle,
description: route.meta.ogDescription,
image: route.meta.ogImage,
type: route.meta.ogType || 'website',
url: route.meta.canonicalUrl,
imageAlt: route.meta.ogImageAlt,
}
Use a head-management mechanism already in your app, or implement a small route-aware update. It should set or replace one value for each property as the active route changes. Make sure navigating to a route without an override falls back to deliberate site defaults or removes the previous route’s values. Otherwise stale tags can remain or duplicate tags can accumulate.
Minimal browser-side update
The following plain JavaScript helper illustrates the required behavior. Call it after the route changes with the selected route’s metadata and canonical URL. For an existing app, a head manager can provide equivalent lifecycle handling.
function setMetaProperty(property, content) {
let element = document.head.querySelector(`meta[property="${property}"]`)
if (!content) {
element?.remove()
return
}
if (!element) {
element = document.createElement('meta')
element.setAttribute('property', property)
document.head.appendChild(element)
}
element.setAttribute('content', content)
}
function updateOpenGraph(meta, canonicalUrl) {
setMetaProperty('og:title', meta.ogTitle)
setMetaProperty('og:type', meta.ogType || 'website')
setMetaProperty('og:url', canonicalUrl)
setMetaProperty('og:image', meta.ogImage)
setMetaProperty('og:description', meta.ogDescription)
setMetaProperty('og:image:alt', meta.ogImageAlt)
}
// Example route hook usage:
// updateOpenGraph(route.meta, new URL(route.fullPath, location.origin).href)
This helper changes the browser’s live document head. It does not make those updates part of the original server response. For a route-specific initial HTML head, render the values on the server or generate each page’s HTML ahead of time.
4. Use absolute, accurate page values
og:url: Use the absolute canonical URL for the page, not a relative path or a URL for a different route. The protocol treats this as the permanent object identifier.og:image: Use an absolute image URL that represents the page. Confirm the URL is correct and the image is publicly fetchable in the deployment environment.og:titleandog:description: Keep both specific to the page. The description should summarize the object in one or two sentences.og:type: Select a type that accurately describes the object, such aswebsitefor a general site page orarticlefor an article.og:image:alt: Describe the image content for people who cannot see it.
Do not assume a platform-specific image size, crawler behavior, or preview cache policy from the Open Graph protocol alone. Those details require current documentation from the particular service where you are sharing the page.
5. Verify the output for each route
- Open the deployed target URL directly, including a nested route, rather than checking only the app’s root page.
- Inspect the document head and confirm there is one current value for each property:
og:title,og:type,og:url,og:image, and your description and image alt text. - Check that the canonical URL is absolute and points to the intended page.
- Open the image URL independently and verify it resolves to the intended public image.
- Inspect the initial HTML response as well as the browser’s live DOM. If the values appear only after Vue runs, decide whether client-side updates meet your requirement or whether SSR/SSG is needed.
- Repeat for a route with metadata overrides, a route inheriting parent metadata, and a route that uses defaults.
A screenshot can help document what a page looks like in a browser, but it does not establish which metadata is present in the HTML head. Verify the actual markup for Open Graph correctness.
6. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Every route shows the same preview title or image | Only shared template tags are set, or route metadata is not applied. | Store values per route or page and bind them to the active URL. Verify a nested route directly. |
| The previous page’s values remain after navigation | The route update does not replace or clear old tags. | Update each property on every route change and remove optional properties that have no value. |
| There are multiple tags for the same property | The implementation appends tags on each navigation instead of updating existing elements. | Use a head manager or query and update the existing element; ensure only one value per property remains. |
| Browser DOM looks correct but the initial HTML does not | Tags are added only after client-side Vue code runs. | Use SSR for request-time data or SSG/prerendering for build-time-known pages when initial HTML must include the metadata. |
| The preview image is missing or wrong | The URL may be relative, incorrect, inaccessible, or associated with another route. | Set an absolute, page-specific image URL and check it independently from the deployed environment. |
| The canonical URL points to the wrong page | A route path was used without the site origin, or a shared default was applied. | Generate or store the full canonical URL for the active page and inspect it on nested routes. |
| Social preview is not refreshed after metadata changes | The service may have its own preview-fetching or caching behavior. | Confirm the current behavior and any refresh procedure in that service’s official documentation. Do not infer cache timing from Open Graph itself. |
7. Performance, reliability, and cost
Static tags add no route-update work. Client-side route updates are small, but they happen only after JavaScript executes and should be checked for stale or duplicate state during navigation. SSR adds server rendering work; SSG moves rendering to the build and is suitable when metadata is known then. Choose based on when page data is available and whether the target needs metadata in the initial response. Vue’s SSR guide discusses the tradeoffs and setup considerations.
For reliability, derive the title, description, image, type, and canonical URL from one page data source where practical. Provide defaults for missing optional values, keep route fallbacks explicit, and inspect generated HTML after deployment. No platform crawler behavior, refresh timing, image-size requirement, or performance benchmark is asserted here because the cited sources do not establish those details.
Adding Open Graph tags uses Vue and HTML capabilities; no paid service is inherently required. Choose SSR or SSG based on application needs and your existing deployment rather than buying a separate metadata tool.
Or skip the browser setup
ScreenshotNeo is a website screenshot API and MCP server for developers. It returns a screenshot or PDF from one GET request, which can help when you need a visual capture of the finished page in addition to checking its HTML metadata. It does not replace inspecting the Open Graph tags themselves. See the ScreenshotNeo API documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://example.com/articles/example -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://example.com/articles/example"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://example.com/articles/example' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
- Cookie and consent banners are accepted or removed before capture; 60+ known consent platforms, newsletter popups, and chat widgets can be removed, and each step can be turned off.
- Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing; response headers say the page verdict and whether the capture was billed.
- An MCP server gives AI agents tools to take screenshots, get page info, and capture PDFs.
- The free plan includes 1,000 screenshots per month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan.
Learn about ScreenshotNeo or sign up for 1,000 free screenshots a month with no card.
FAQ
Are Open Graph tags Vue-specific?
No. They are HTML metadata properties defined by the Open Graph Protocol. Vue determines how your app supplies them to the document head.
Can a parent Vue Router route provide defaults?
Yes. Vue Router merges parent and child route metadata into the matched route’s route.meta value. Child values can provide page-specific data; your head integration still has to render the result.
Should every page use og:type="website"?
Use a type that accurately describes the object. A general site page can use website; an article can use article.
Does a screenshot confirm that sharing metadata is correct?
No. A screenshot shows visual output. Inspect the HTML head and the initial response to confirm metadata.


