next-meta
v0.5.0
Published
A composable React component for managing meta tags, Open Graph, and X/Twitter cards in Next.js applications.
Downloads
349
Maintainers
Readme
🗣️ next-meta
A composable metadata layer for Next.js: native metadata objects for App Router, Head components for Pages Router, and a dependency-free shared core.
Documentation · Getting started · API reference
The documentation site lives in the private docs workspace. Run pnpm run docs:dev for local development or pnpm run docs:build to verify the static export. See deployment guidance for next-meta.dev, Springbar, and social-image capture routes.
Why next-meta?
Managing meta tags, Open Graph, and Twitter cards in Next.js applications can be tedious and error-prone. next-meta provides a simple, composable solution that:
- Reduces boilerplate code for meta tag management
- Ensures consistent meta tag structure across your application
- Provides TypeScript support out of the box
- Handles all major social media platforms (Open Graph, Twitter Cards, Pinterest)
- Supports dynamic meta tags based on page content
- Maintains SEO best practices
- Pairs with
react-structuredfor Schema.org structured data
Install
Via npm
npm install next-metaVia Yarn
yarn add next-metaApp Router (Next.js 14+)
Use the server-safe next-meta/app entry point. It does not import React or
next/head at runtime. Next.js owns rendering and streaming the returned metadata.
// app/layout.tsx
import { defineMeta, toMetadata, toViewport } from 'next-meta/app'
export const siteMeta = defineMeta({
baseUrl: 'https://example.com',
title: { default: 'Example', template: '%s | Example' },
description: 'Example documentation',
images: ['/social/default.png'],
twitter: { card: 'summary_large_image', site: '@example' },
})
export const metadata = toMetadata(siteMeta)
export const viewport = toViewport({
width: 'device-width',
initialScale: 1,
themeColor: [
{ media: '(prefers-color-scheme: light)', color: 'white' },
{ media: '(prefers-color-scheme: dark)', color: 'black' },
],
})// app/docs/[slug]/page.tsx (Next.js 15+ asynchronous params)
import type { Metadata, ResolvingMetadata } from 'next'
import { toMetadata } from 'next-meta/app'
export async function generateMetadata(
{ params }: { params: Promise<{ slug: string }> },
parent: ResolvingMetadata,
): Promise<Metadata> {
const { slug } = await params
return toMetadata(
{
title: slug,
canonical: `/docs/${slug}`,
url: `/docs/${slug}`,
images: [{ url: `/social/${slug}.png`, alt: slug }],
composeMeta: { images: true },
},
{ parent: await parent },
)
}parent explicitly supplies the parent's base URL, description, site name,
locale and images. It does not copy the parent's already-resolved title; Next
applies layout title templates. For other shared values, pass defaults with a
reusable configuration. A page title is not automatically suffixed with
siteName in App Router; declare a native layout title template instead.
Arrays replace inherited values by default. composeMeta appends defaults after
page values and deduplicates media by URL. An explicit empty array clears an
inherited array. Both router adapters use the same core normalization, merge,
URL resolution and Twitter fallback pipeline. Both accept image URL shorthand;
App Router additionally accepts native title objects.
toMetadata(config, { native: { robots: { index: false }, icons: '/icon.png' } })
accepts any native Next.js metadata. Native top-level fields replace mapped
fields last, including the entire openGraph or twitter object when supplied.
The adapter maps common social metadata, article/book/profile, music and video
types, Twitter summary/app/player cards, and Pinterest verification. Twitter
players must provide a player URL, stream URL and positive dimensions. Legacy
extensions such as payment.link, product/location tags, arbitrary
additionalMetaTags, and per-platform Twitter app names/country are Pages-only;
use native fields where Next supports equivalents. Unsupported Open Graph
types throw unless native.openGraph replaces them.
Native file conventions (opengraph-image, twitter-image, icons, robots,
sitemap and manifest) remain Next.js-owned. File-based metadata can override
configured metadata. next-meta does not generate these files or render JSON-LD;
use a focused structured-data library alongside it.
Shared core and focused imports
import {
defineMeta,
normalizeMeta,
mergeMeta,
resolveMeta,
} from 'next-meta/core'
const defaults = defineMeta({
baseUrl: 'https://example.com',
siteName: 'Example',
})
const page = mergeMeta(defaults, { title: 'Guide', canonical: '/guide' })
const resolved = resolveMeta(page)
// resolved.canonical === 'https://example.com/guide'
// resolved.documentTitle === 'Guide | Example'MetaConfig and ResolvedMeta are router-neutral, serializable metadata models.
The core supports string titles and image URL strings or descriptors.
AppMetaConfig adds native title objects. normalizeMeta handles deprecated
aliases; mergeMeta safely combines configurations without mutating inputs;
resolveMeta(config, { defaults }) additionally resolves URLs and fallbacks.
Structured validation and expanded parent policies are reserved for later work.
| Import | Use | Runtime dependencies |
| ----------------- | ------------------------------------------------ | ------------------------- |
| next-meta/core | Shared config, build scripts, resolved snapshots | None |
| next-meta/app | Native Metadata / Viewport on Next.js 14+ | None (Next types only) |
| next-meta/pages | Pages Router components on Next.js 10+ | React, React DOM, Next.js |
| next-meta | Existing root API, unchanged | React, React DOM, Next.js |
Next.js 14, 15 and 16 are exercised by the packed-consumer integration matrix. Keep Next.js updated to a patched release independently of this library.
Release checks
Use Node from .nvmrc and the pnpm version in packageManager. Run
pnpm run release:check before publishing: it checks the advisory budget, lint,
formatting, types, unit coverage, builds, real Next Head behavior and a clean
packed consumer. The packed consumer verifies server-only imports without React
or Next installed, ESM/CommonJS exports, root/pages context identity, strict
declarations and static/dynamic App Router plus Pages Router production HTML.
Set NEXT_VERSION=15 pnpm run release:smoke to exercise another Next major.
Failed smoke artifacts are retained in the printed temporary directory for
diagnosis. CI tests Next 14/15/16; publishing runs the complete default check.
The version bump and changelog remain explicit release preparation steps.
Publish uses the package version to select next for prereleases and latest
for stable releases; a release tag must match that version. A manually dispatched
publish workflow validates and dry-runs only.
GitHub Actions publishing setup
Publishing uses npm trusted publishing
with GitHub OIDC, not a stored npm token. In the next-meta package settings on
npm, configure a GitHub Actions trusted publisher with:
- Organization or user:
ryanhefner. - Repository:
next-meta. - Workflow filename:
publish.yml(not its full path). - Environment name: leave blank; the publish job does not use a GitHub environment.
- Allow direct publishing with
npm publish.
No NODE_AUTH_TOKEN or NPM_TOKEN secret is required. The workflow grants
id-token: write and runs on a GitHub-hosted runner with Node 24; npm trusted
publishing requires npm 11.5.1 or newer. Configuring this relationship requires
an authenticated npm account with write access to the package. A successful
manual dry run validates the artifact, but does not prove npm publishing
authorization.
After merging the prepared release and passing CI, publish a GitHub Release
tagged v0.5.0 from the commit containing package.json version 0.5.0.
That release event publishes the package with the latest dist-tag; manually
dispatching the workflow does not publish. Deploy the docs separately using
the Vercel setup.
Strict NodeNext declaration checks allow only existing Next.js-internal missing Satori/emoji/Sharp/URLPattern declarations, by exact file and diagnostic. No consumer or next-meta declaration errors are suppressed. The dependency-free shared-core fixture also has a cold compilation budget of 200,000 type instantiations, checked independently of Next.js and React types.
Pages Router
Basic Setup
Setting defaults within the Next.js App with MetaProvider.
import type { ReactElement, ReactNode } from 'react'
import type { NextPage } from 'next'
import type { AppProps } from 'next/app'
import Head from 'next/head'
import { useRouter } from 'next/router'
import { MetaProvider } from 'next-meta'
// eslint-disable-next-line @typescript-eslint/ban-types
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
getLayout?: (page: ReactElement) => ReactNode
}
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout
}
const BASE_URL = 'https://test.com'
const SITE_NAME = 'Example Site'
const DEFAULT_TITLE = 'An example title for using next-meta in your _app file.'
const DEFAULT_DESCRIPTION =
'Hopefully this makes things a little easier with adding good meta/og tags to your site.'
const DEFAULT_IMAGE = {
url: '/social-share.png',
alt: 'Default social share image',
width: 1200,
height: 630,
}
function CustomApp({ Component, pageProps }: AppPropsWithLayout) {
const getLayout = Component.getLayout ?? ((page) => page)
const { asPath: metaUrl } = useRouter()
return (
<>
<Head>
<link rel="icon" type="image/png" href="/favicon.ico" />
</Head>
<MetaProvider
skipRepeatableDefaultsRender
baseUrl={BASE_URL}
canonical={metaUrl}
description={DEFAULT_DESCRIPTION}
images={[DEFAULT_IMAGE]}
siteName={SITE_NAME}
title={DEFAULT_TITLE}
twitter={{
card: 'summary_large_image',
site: '@exampleSite',
}}
url={metaUrl}
>
{getLayout(<Component {...pageProps} />)}
</MetaProvider>
</>
)
}
export default CustomAppPage-Specific Meta Tags
Specify page-specific meta tags with PageMeta. It renders through
next/head, so it should not be wrapped in another Head component.
import { PageMeta } from 'next-meta'
const ExamplePage = () => {
return (
<>
<PageMeta
images={[
{
url: '/share/about-social.png',
alt: 'About page social share image',
width: 1200,
height: 630,
},
]}
title="About"
siteName="Example Site"
url="/about"
/>
{/* ...page code... */}
</>
)
}Advanced Usage
Here's an example showing more advanced features:
import { PageMeta } from 'next-meta'
const BlogPost = ({ post }) => {
return (
<>
<PageMeta
title={post.title}
description={post.excerpt}
images={[
{
url: post.featuredImage,
alt: post.featuredImageAlt,
width: 1200,
height: 630,
},
]}
url={`/blog/${post.slug}`}
twitter={{
card: 'summary_large_image',
creator: '@authorHandle',
}}
audio={
post.audioUrl
? [{ url: post.audioUrl, type: 'audio/mpeg' }]
: undefined
}
videos={
post.videoUrl
? [
{
url: post.videoUrl,
type: 'video/mp4',
width: 1920,
height: 1080,
},
]
: undefined
}
locale="en_US"
determiner="the"
article={{
author: post.authors,
publishedTime: post.publishedAt,
modifiedTime: post.updatedAt,
section: 'Technology',
tag: post.tags,
}}
/>
{/* ...post content... */}
</>
)
}Schema.org Structured Data
next-meta focuses on meta tags, Open Graph, and social card metadata. For
Schema.org structured data, use
react-structured alongside
next-meta. When both packages are installed, React 16.14 or newer is required by
their combined peer dependency ranges.
npm install react-structuredyarn add react-structuredPages Router
Render the structured-data component alongside PageMeta. Do not nest it inside
PageMeta or next/head: Next.js requires scripts inside Head to be direct
children, while JSON-LD is valid in the document body.
import { PageMeta } from 'next-meta'
import { Schema } from 'react-structured'
const BlogPost = ({ post, nonce }) => {
const articleUrl = new URL(
`/blog/${post.slug}`,
'https://example.com',
).toString()
return (
<>
<PageMeta
title={post.title}
description={post.excerpt}
images={[{ url: post.featuredImage }]}
canonical={articleUrl}
url={articleUrl}
/>
<Schema
id="article-jsonld"
nonce={nonce}
type="Article"
data={{
headline: post.title,
image: post.featuredImage,
mainEntityOfPage: articleUrl,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
author: {
'@type': 'Person',
name: post.author.name,
},
publisher: {
'@type': 'Organization',
name: 'My Blog',
},
}}
/>
{/* ...post content... */}
</>
)
}Give each JSON-LD script a stable, document-unique id for inspection and
testing. Pass nonce when the application's Content Security Policy requires
one; otherwise omit it. Reuse the same absolute canonical and media URLs in
metadata and structured data so they cannot disagree.
App Router
next-meta v0.4 targets Pages Router. In App Router today, use Next.js's native
Metadata API and continue rendering react-structured in the page or layout.
The planned next-meta App Router adapter will replace only the metadata
construction in this pattern; JSON-LD will remain a sibling component.
// app/articles/example/page.tsx
import type { Metadata } from 'next'
import { Schema } from 'react-structured'
const ARTICLE_URL = 'https://example.com/articles/example'
const ARTICLE_IMAGE = 'https://example.com/articles/example/social.jpg'
export const metadata: Metadata = {
title: 'Example article',
alternates: { canonical: ARTICLE_URL },
openGraph: {
type: 'article',
url: ARTICLE_URL,
images: [ARTICLE_IMAGE],
},
}
export default function ArticlePage() {
return (
<>
<Schema
id="article-jsonld"
type="Article"
data={{
headline: 'Example article',
image: ARTICLE_IMAGE,
mainEntityOfPage: ARTICLE_URL,
}}
/>
<main>{/* ...article content... */}</main>
</>
)
}See the
react-structured README
for more Schema.org examples and TypeScript usage.
TypeScript Support
next-meta is written in TypeScript and provides type definitions out of the box. The package exports the following types:
PageMetaProps: Props for the PageMeta componentMetaProviderProps: Props for the MetaProvider componentSiteMetaProps: Deprecated compatibility alias forPageMetaPropsComposeMetaOptions: Controls repeatable metadata compositionImage: Type for image objectsVideo: Type for video objectsAudio: Type for audio objectsMetaTag: Type for additional meta tag objectsMetaContent: Type for additional meta tag contentMusicReference: Type for music song and album referencesTwitter: Type for Twitter card configurationTwitterApp: Type for Twitter app card platform configurationTwitterCard: Enum for Twitter card types
Components
PageMeta
Renders page metadata through next/head. It accepts PageMetaProps, including
custom children such as alternate feed links.
MetaProvider
Provides default PageMetaProps to descendant PageMeta components.
Use <MetaProvider skipRepeatableDefaultsRender> when pages render PageMeta.
The provider still emits singleton defaults (title, description, canonical,
etc.), and pages overwrite those named tags normally. The composable
images, audio, videos, localeAlternates and additionalMetaTags arrays
are deferred to the page renderer, along with repeatable author, tag,
restriction, see-also and nested article/book/music fields. Their singleton
siblings (for example article publication dates) continue rendering through
the provider. All defaults remain in context:
<PageMeta /> inherits them, a supplied array replaces them, and an empty array
clears them. Every page must render PageMeta to receive deferred arrays.
This prevents stale provider-array entries without skipping singleton defaults.
skipDefaultsRender is still available when you prefer one renderer for all
tags. Both flags default to false for compatibility with provider-only rendering.
| Prop | Description |
| ---------------------------------------- | ------------------------------------------------------------------ |
| All PageMetaProps | Default metadata inherited by descendant PageMeta components. |
| skipDefaultsRender?: boolean | Provide defaults without immediately rendering a separate tag set. |
| skipRepeatableDefaultsRender?: boolean | Render singleton defaults; defer composable arrays to pages. |
| children?: ReactNode | Application or page content that receives the defaults. |
SiteMeta (deprecated)
SiteMeta remains a compatibility alias for PageMeta during the v0.x
migration period. New code should use PageMeta.
Migrating from v0.3
v0.4 uses repeatable media arrays and groups X/Twitter settings under
twitter. The v0.3 names remain available as deprecated compatibility aliases,
but new code should use the current API:
| Deprecated v0.3 API | Current v0.4 API |
| ---------------------------------------------- | ---------------------------------------- |
| SiteMeta | PageMeta |
| SiteMetaProps | PageMetaProps |
| image or imageUrl, imageAlt, dimensions | images={[{ url, alt, width, height }]} |
| audioUrl, audioType | audio={[{ url, type }]} |
| videoUrl, videoType | videos={[{ url, type }]} |
| twitterCard, twitterCreator, twitterSite | twitter={{ card, creator, site }} |
| debug | No replacement; the option was a no-op. |
When current and deprecated image props are both supplied, images takes
precedence over image, and fields in image take precedence over their flat
deprecated equivalents. Nested twitter fields likewise take precedence over
the flat Twitter props.
Properties
next-meta supports the current Open Graph protocol basics, structured image,
audio, and video properties, and the object-type namespaces for article,
book, profile, music, video, and payment.link. For custom, uncommon,
or platform-specific meta tags, use additionalMetaTags.
Core Properties
| Prop | Description | Example |
| ---------------------------------- | -------------------------------------------------------- | ----------------------------------------------- |
| additionalMetaTags?: MetaTag[] | Additional custom meta tags. | [{ name: "robots", content: "index,follow" }] |
| baseUrl?: string | Base URL for all relative URLs. | "https://example.com" |
| canonical?: string | Canonical URL for the page. | "/blog/post-1" |
| composeMeta?: ComposeMetaOptions | Compose repeatable provider metadata into page metadata. | { images: true } |
| debug?: boolean | Deprecated no-op retained for compatibility. | true |
| description?: string | Page description for meta tags. | "Learn about our company" |
| determiner?: string | Word before object's title in a sentence. | "the" |
| locale?: string | Locale of site/page. | "en_US" |
| localeAlternates?: string[] | Alternate locales for the page. | ["en_CA", "fr_CA"] |
| siteName?: string | Site name for meta tags. | "My Blog" |
| siteNameDelimiter?: string | Delimiter between title and site name. | " - " |
| title?: string | Page title. | "About Us" |
| twitter?: Twitter | X/Twitter card overrides and configuration. | { card: "summary_large_image" } |
| type?: string | Open Graph type of the page. | "website" |
| url?: string | URL of page. | "/about" |
| pinterestDomainVerify?: string | Pinterest domain verification code. | "abc123xyz" |
Relative values for canonical, url, and media URLs are resolved against
baseUrl with the standard URL constructor. A trailing slash on a directory
base is significant: new URL('guide', 'https://example.com/docs/') resolves to
https://example.com/docs/guide.
Composing Repeatable Metadata
By default, page-level array props replace provider-level array props. To render
page-specific tags first and then append matching provider defaults, opt in with
composeMeta on MetaProvider:
<MetaProvider
skipRepeatableDefaultsRender
composeMeta={{ images: true }}
images={[{ url: '/default-og.png', alt: 'Default share image' }]}
>
<PageMeta
title="Post title"
images={[{ url: '/post-og.png', alt: 'Post share image' }]}
/>
</MetaProvider>This renders the page image first, followed by the provider image. PageMeta
can override the provider policy for one page:
<PageMeta composeMeta={{ images: false }} images={[{ url: '/post-og.png' }]} />Supported composition fields are images, audio, videos,
localeAlternates, and additionalMetaTags. You can also pass
composeMeta={true} as shorthand for all supported fields. Passing an explicit
empty array, such as images={[]}, clears inherited values even when
composition is enabled.
Use skipRepeatableDefaultsRender to prevent provider arrays from rendering
separately from the final page arrays. Singleton defaults still render.
Explicit prepend, append and replace policies work across the five
composable arrays:
<PageMeta composeMeta={{ images: 'append', audio: 'replace' }} images={['/page.png']} />
// Images: provider values first, followed by page values.
<PageMeta images={{ items: ['/page.png'], mode: 'prepend' }} />
// Images: page values first, followed by provider values.
<PageMeta images={{ items: ['/page.png'], mode: 'replace' }} />
// Images: exactly the supplied list, even if the defaults had more entries.Images accept URL strings and descriptors. The inline image policy takes
precedence over composeMeta.images. true retains its existing meaning
(prepend); false means replace. Media deduplication keeps the first value
for each URL. Empty arrays clear inherited values in every mode. Null/undefined
tags are not deletion markers; selective provider deferral makes the final
rendered list authoritative.
Media Properties
| Prop | Description | Example |
| ------------------ | ------------------------------------------ | --------------------------------------------------------------------------------- |
| images?: Image[] | Array of image objects for social sharing. | [{ url: "/images/share.png", alt: "Description", width: 1200, height: 630 }] |
| audio?: Audio[] | Array of audio objects. | [{ url: "/podcast/episode1.mp3", type: "audio/mpeg", title: "Episode 1" }] |
| videos?: Video[] | Array of video objects. | [{ url: "/videos/tutorial.mp4", type: "video/mp4", width: 1920, height: 1080 }] |
Image Object
| Property | Type | Description |
| ----------- | ------------------ | ---------------------- |
| url | string | URL of the image |
| alt | string | Alt text for the image |
| secureUrl | string | HTTPS URL of the image |
| width | number \| string | Width of the image |
| height | number \| string | Height of the image |
| type | string | MIME type of the image |
Video Object
| Property | Type | Description |
| ------------- | ----------------------------------------- | ------------------------- |
| url | string | URL of the video |
| secureUrl | string | HTTPS URL of the video |
| type | string | MIME type of the video |
| width | number \| string | Width of the video |
| height | number \| string | Height of the video |
| duration | number \| string | Duration in seconds |
| actor | Array<{ name?: string; role?: string }> | Actors in the video |
| director | string \| string[] | Director(s) of the video |
| writer | string \| string[] | Writer(s) of the video |
| releaseDate | string | Release date of the video |
| tag | string \| string[] | Tags for the video |
| series | string | Series name if applicable |
Other Video Properties
Use videoOther for the og:video:other extension and its optional stream
metadata.
| Property | Type | Description |
| ------------------------------- | ------------------ | --------------------- |
| videoOther.url | string | Other video URL |
| videoOther.secureUrl | string | HTTPS other video URL |
| videoOther.type | string | Other video MIME type |
| videoOther.width | number \| string | Other video width |
| videoOther.height | number \| string | Other video height |
| videoOther.duration | number \| string | Other video duration |
| videoOther.stream.url | string | Stream URL |
| videoOther.stream.secureUrl | string | HTTPS stream URL |
| videoOther.stream.contentType | string | Stream MIME type |
| videoOther.stream.width | number \| string | Stream width |
| videoOther.stream.height | number \| string | Stream height |
| videoOther.stream.duration | number \| string | Stream duration |
Audio Object
| Property | Type | Description |
| ----------- | -------------------- | --------------------------- |
| url | string | URL of the audio file |
| secureUrl | string | HTTPS URL of the audio file |
| type | string | MIME type of the audio file |
| duration | number \| string | Duration in seconds |
| title | string | Title of the audio |
| artist | string \| string[] | Artist(s) of the audio |
| album | string | Album name |
Twitter Object
| Property | Type | Description |
| ------------- | ------------ | ------------------------------ |
| card | string | Twitter card type |
| title | string | Twitter-specific title |
| description | string | Twitter-specific description |
| site | string | Twitter username for site |
| siteId | string | Twitter numeric site ID |
| creator | string | Twitter username for author |
| creatorId | string | Twitter numeric creator ID |
| image | Image | Twitter-specific image and alt |
| app | TwitterApp | App card configuration |
| player | Player | Player card configuration |
Twitter Card Types
When using the twitter.card property, you can use one of the following values:
"summary"- Default card type"summary_large_image"- Large image card type"app"- App card type"player"- Player card type
Twitter App Object
| Property | Type | Description |
| ------------ | ------------ | ----------------------------- |
| country | string | App Store country code |
| name | string | Fallback app name |
| iPhone | TwitterApp | iPhone app card metadata |
| iPad | TwitterApp | iPad app card metadata |
| googlePlay | TwitterApp | Google Play app card metadata |
Twitter App Platform Object
| Property | Type | Description |
| -------- | -------- | ---------------------------- |
| name | string | Platform-specific app name |
| id | string | Platform-specific app ID |
| url | string | Platform-specific custom URL |
Player Object
| Property | Type | Description |
| -------- | ------------------ | -------------------- |
| url | string | URL of the player |
| width | number \| string | Width of the player |
| height | number \| string | Height of the player |
| stream | Stream | Stream configuration |
Stream Object
| Property | Type | Description |
| ------------- | -------- | -------------------------- |
| url | string | URL of the stream |
| contentType | string | Content type of the stream |
General Metadata Properties
| Prop | Type | Description |
| ---------------- | -------------------- | ---------------------------- |
| author | string \| string[] | Author(s) of the content |
| updatedTime | string | Last updated time (ISO 8601) |
| seeAlso | string \| string[] | Related URLs |
| richAttachment | boolean | Enable rich attachment |
| tag | string \| string[] | Tags for the content |
| section | string | Section of the site |
| publishedTime | string | Publication time (ISO 8601) |
| modifiedTime | string | Modification time (ISO 8601) |
| releaseDate | string | Release date |
| expirationTime | string | Expiration time (ISO 8601) |
| startTime | string | Start time (ISO 8601) |
| endTime | string | End time (ISO 8601) |
Location Properties
| Prop | Type | Description |
| --------------- | ------------------ | -------------------- |
| latitude | number \| string | Latitude coordinate |
| longitude | number \| string | Longitude coordinate |
| streetAddress | string | Street address |
| locality | string | City or locality |
| region | string | State or region |
| postalCode | string | Postal/ZIP code |
| countryName | string | Country name |
Contact Properties
| Prop | Type | Description |
| ------------- | -------- | ------------- |
| email | string | Email address |
| phoneNumber | string | Phone number |
| faxNumber | string | Fax number |
Product/Rating Properties
| Prop | Type | Description |
| --------------- | ---------------------------------------------------------------------------------- | ------------------------ |
| price | string \| number | Price of the product |
| availability | string | Availability status |
| isbn | string | ISBN for books |
| rating | { value?: number \| string; scale?: number \| string; count?: number \| string } | Rating information |
| reviewCount | number \| string | Number of reviews |
| points | number \| string | Points/rewards |
| restrictions | string \| string[] | Age/content restrictions |
| ageRating | string | Age rating |
| contentRating | string | Content rating |
Article-Specific Properties
| Prop | Type | Description |
| ------------------------ | -------------------- | ---------------------------- |
| article.author | string \| string[] | Article author(s) |
| article.publishedTime | string | Publication time (ISO 8601) |
| article.modifiedTime | string | Modification time (ISO 8601) |
| article.expirationTime | string | Expiration time (ISO 8601) |
| article.section | string | Article section |
| article.tag | string \| string[] | Article tags |
Book-Specific Properties
| Prop | Type | Description |
| ------------------ | -------------------- | -------------- |
| book.author | string \| string[] | Book author(s) |
| book.isbn | string | ISBN |
| book.releaseDate | string | Release date |
| book.tag | string \| string[] | Book tags |
Profile-Specific Properties
| Prop | Type | Description |
| ------------------- | -------- | ----------- |
| profile.firstName | string | First name |
| profile.lastName | string | Last name |
| profile.username | string | Username |
| profile.gender | string | Gender |
Music-Specific Properties
| Prop | Type | Description |
| ------------------- | ------------------------------------ | ----------------------- |
| music.duration | number \| string | Duration in seconds |
| music.album | MusicReference \| MusicReference[] | Album reference(s) |
| music.song | MusicReference \| MusicReference[] | Song reference(s) |
| music.musician | string \| string[] | Musician profile URL(s) |
| music.creator | string \| string[] | Creator profile URL(s) |
| music.releaseDate | string | Release date |
Music Reference Object
| Property | Type | Description |
| -------- | ------------------ | ----------------- |
| url | string | Song or album URL |
| disc | number \| string | Disc number |
| track | number \| string | Track number |
Payment-Specific Properties
| Prop | Type | Description |
| --------------------- | ------------------ | ------------------------ |
| payment.description | string | Payment link description |
| payment.currency | string | ISO 4217 currency code |
| payment.amount | number \| string | Payment amount |
| payment.expiresAt | string | Expiration datetime |
| payment.status | string | Payment status |
| payment.id | string | Payment identifier |
| payment.successUrl | string | Success redirect URL |
Additional Meta Tags
| Property | Type | Description |
| ----------- | ----------------------------- | ------------------------------- |
| name | string | Renders a name meta tag |
| property | string | Renders a property meta tag |
| httpEquiv | string | Renders an HTTP-equiv tag |
| itemProp | string | Renders an itemprop meta tag |
| charSet | string | Renders a charset meta tag |
| lang | string | Language for localized metadata |
| media | string | Media query for supported tags |
| scheme | string | Legacy metadata scheme |
| content | string \| number \| boolean | Meta tag content |
