OpenGraph
OpenGraph renders a complete set of Open Graph meta tags with a type-safe API. It infers the primary og:type from a single type-driving object, lets you override that value explicitly, and outputs media and namespace tags based on the props you provide.
| prop | type | default | required | description |
|---|---|---|---|---|
title | string | - | Yes | Main Open Graph title rendered as og:title. |
type | string | false | inferred from the type-driving object or website | No | Overrides the inferred og:type value when set to a string, or omits the og:type tag entirely when set to false. |
url | string | URL | derived from current request when Astro.site exists | No | Canonical page URL rendered as og:url. |
description | string | - | No | Description rendered as og:description. |
siteName | string | integration head.openGraph.siteName | No | Site label rendered as og:site_name. |
locale | string | - | No | Open Graph locale value rendered as og:locale (for example en_US). |
localeAlternate | string[] | [] | No | Alternate locale values, each rendered as og:locale:alternate. |
image | ComponentProps<typeof OpenGraphImage> | - | No | Structured image metadata rendered as og:image tags. |
audio | ComponentProps<typeof OpenGraphAudio> | - | No | Structured audio metadata rendered as og:audio tags. |
video | ComponentProps<typeof OpenGraphVideo> | - | No | Structured video metadata rendered as og:video tags. |
article | ComponentProps<typeof OpenGraphArticle> | - | No | Type-driving article object; sets og:type=article. |
book | ComponentProps<typeof OpenGraphBook> | - | No | Type-driving book object; sets og:type=book. |
business | ComponentProps<typeof OpenGraphBusiness> | - | No | Business namespace tags; keeps og:type=website. |
music | ComponentProps<typeof OpenGraphMusic> | - | No | Type-driving music object; sets og:type=music.<subtype>. |
place | ComponentProps<typeof OpenGraphPlace> | - | No | Place namespace tags; keeps og:type=website. |
product | ComponentProps<typeof OpenGraphProduct> | - | No | Product namespace tags; keeps og:type=website. |
profile | ComponentProps<typeof OpenGraphProfile> | - | No | Type-driving profile object; sets og:type=profile. |
videoType | ComponentProps<typeof OpenGraphVideoType> | - | No | Type-driving video object; sets og:type=video.<subtype>. |
Examples
Section titled “Examples”Input:
<OpenGraph title="Home" url="https://example.com/" siteName="Example" />Output:
<meta property="og:type" content="website" /><meta property="og:title" content="Home" /><meta property="og:url" content="https://example.com/" /><meta property="og:site_name" content="Example" />Automatic
Section titled “Automatic”Automatically derives og:url from the current request when Astro.site is configured.
Input:
<OpenGraph title="Home" />Output (when site context is available):
<meta property="og:type" content="website" /><meta property="og:title" content="Home" /><meta property="og:url" content="https://example.com/current/path" />Complete
Section titled “Complete”Input:
<OpenGraph title="My Article" url="https://example.com/posts/1" description="Open Graph overview" siteName="Example" locale="en_US" localeAlternate={["es_ES", "fr_FR"]} image={{ src: "https://example.com/og.png", width: 1200, height: 630, alt: "Banner", }} article={{ publishedTime: "2026-01-01T00:00:00Z", authors: ["https://example.com/author"], section: "Tech", tags: ["astro", "seo"], }}/>Output:
<meta property="og:type" content="article" /><meta property="og:title" content="My Article" /><meta property="og:url" content="https://example.com/posts/1" /><meta property="og:description" content="Open Graph overview" /><meta property="og:site_name" content="Example" /><meta property="og:locale" content="en_US" /><meta property="og:locale:alternate" content="es_ES" /><meta property="og:locale:alternate" content="fr_FR" /><meta property="og:image" content="https://example.com/og.png" /><meta property="og:image:type" content="image/png" /><meta property="og:image:width" content="1200" /><meta property="og:image:height" content="630" /><meta property="og:image:alt" content="Banner" /><meta property="article:published_time" content="2026-01-01T00:00:00Z" /><meta property="article:author" content="https://example.com/author" /><meta property="article:section" content="Tech" /><meta property="article:tag" content="astro" /><meta property="article:tag" content="seo" />Decisions Made
Section titled “Decisions Made”Explicit type prop takes precedence
Section titled “Explicit type prop takes precedence”When type is provided as a string, OpenGraph uses that value instead of the inferred one. For example, <OpenGraph title="Home" type="article" /> renders og:type=article even without an article object, and <OpenGraph title="Home" type={false} /> omits the og:type tag entirely.
og:type inference is deterministic
Section titled “og:type inference is deterministic”When type is omitted, the component picks og:type from the type-driving object in this canonical order: article, book, profile, music, videoType, and then website fallback. This keeps output predictable and avoids ambiguous type combinations.
Non-canonical namespaces keep website as og:type
Section titled “Non-canonical namespaces keep website as og:type”Business, place, and product render their namespace-specific tags while og:type remains website. This follows the component’s explicit behavior for OG namespaces that do not map to a canonical top-level og:type value.
URL can be inferred from request context
Section titled “URL can be inferred from request context”When url is omitted, the component builds it from the current path, query, and hash using Astro.site as the base. This removes repetitive per-page URL wiring in common setups.
Locale values are passed through as provided
Section titled “Locale values are passed through as provided”The component does not normalize locale formats. You should provide Open Graph locale values such as en_US and es_ES directly.
Source code
Section titled “Source code”---import type { ComponentProps } from "astro/types";
import { toHref } from "../utils";import OpenGraphArticle from "./openGraph/OpenGraphArticle.astro";import OpenGraphAudio from "./openGraph/OpenGraphAudio.astro";import OpenGraphBook from "./openGraph/OpenGraphBook.astro";import OpenGraphBusiness from "./openGraph/OpenGraphBusiness.astro";import OpenGraphImage from "./openGraph/OpenGraphImage.astro";import OpenGraphMusic from "./openGraph/OpenGraphMusic.astro";import OpenGraphPlace from "./openGraph/OpenGraphPlace.astro";import OpenGraphProduct from "./openGraph/OpenGraphProduct.astro";import OpenGraphProfile from "./openGraph/OpenGraphProfile.astro";import OpenGraphVideo from "./openGraph/OpenGraphVideo.astro";import OpenGraphVideoType from "./openGraph/OpenGraphVideoType.astro";import config from "virtual:eminence-astro-suite/head-tags";
type BaseProps = { title: string; /** * Overrides inferred `og:type`; set to `false` to omit the tag entirely. */ type?: string | false; /** * Defaults to the current page URL when `Astro.site` is configured. */ url?: string | URL; description?: string; /** * Defaults to the integration-level `head.openGraph.siteName` value. */ siteName?: string; /** * Passed through as provided; use Open Graph format values like `en_US`. */ locale?: string; /** * Each entry emits an `og:locale:alternate` tag in Open Graph format. */ localeAlternate?: string[]; /** * Optional rich preview image metadata for social cards. */ image?: ComponentProps<typeof OpenGraphImage>; audio?: ComponentProps<typeof OpenGraphAudio>; video?: ComponentProps<typeof OpenGraphVideo>;};
type TypedVariant = | { article: ComponentProps<typeof OpenGraphArticle>; book?: never; business?: never; music?: never; place?: never; product?: never; profile?: never; videoType?: never; } | { article?: never; book: ComponentProps<typeof OpenGraphBook>; business?: never; music?: never; place?: never; product?: never; profile?: never; videoType?: never; } | { article?: never; book?: never; business: ComponentProps<typeof OpenGraphBusiness>; music?: never; place?: never; product?: never; profile?: never; videoType?: never; } | { article?: never; book?: never; business?: never; music: ComponentProps<typeof OpenGraphMusic>; place?: never; product?: never; profile?: never; videoType?: never; } | { article?: never; book?: never; business?: never; music?: never; place: ComponentProps<typeof OpenGraphPlace>; product?: never; profile?: never; videoType?: never; } | { article?: never; book?: never; business?: never; music?: never; place?: never; product: ComponentProps<typeof OpenGraphProduct>; profile?: never; videoType?: never; } | { article?: never; book?: never; business?: never; music?: never; place?: never; product?: never; profile: ComponentProps<typeof OpenGraphProfile>; videoType?: never; } | { article?: never; book?: never; business?: never; music?: never; place?: never; product?: never; profile?: never; videoType?: ComponentProps<typeof OpenGraphVideoType>; } | { article?: never; book?: never; business?: never; music?: never; place?: never; product?: never; profile?: never; videoType?: never; };type Props = BaseProps & TypedVariant;
const { title, type, url, description, siteName = config.openGraphSiteName, image, audio, video, locale, localeAlternate = [], article, book, business, music, place, product, profile, videoType,} = Astro.props;
const inferredUrl = Astro.site ? new URL(Astro.url.pathname + Astro.url.search + Astro.url.hash, Astro.site) .href : undefined;const resolvedUrl = url ? toHref(url) : inferredUrl;
const inferredType = (() => { // Canonical OG types take precedence; non-canonical namespaces keep website. if (article) return "article"; if (book) return "book"; if (profile) return "profile"; if (music) return `music.${music.subtype}`; if (videoType) return `video.${videoType.subtype}`; return "website";})();const resolvedType = type === undefined ? inferredType : type;---
{resolvedType !== false && <meta property="og:type" content={resolvedType} />}{title && <meta property="og:title" content={title} />}{resolvedUrl && <meta property="og:url" content={resolvedUrl} />}{description && <meta property="og:description" content={description} />}{siteName && <meta property="og:site_name" content={siteName} />}{locale && <meta property="og:locale" content={locale} />}{ localeAlternate.map((locale) => ( <meta property="og:locale:alternate" content={locale} /> ))}{image && <OpenGraphImage {...image} />}{audio && <OpenGraphAudio {...audio} />}{video && <OpenGraphVideo {...video} />}{article && <OpenGraphArticle {...article} />}{book && <OpenGraphBook {...book} />}{business && <OpenGraphBusiness {...business} />}{music && <OpenGraphMusic {...music} />}{place && <OpenGraphPlace {...place} />}{product && <OpenGraphProduct {...product} />}{profile && <OpenGraphProfile {...profile} />}{videoType && <OpenGraphVideoType {...videoType} />}