Unhead Schema.org
Overview
Unhead Schema.org generates a JSON-LD graph from TypeScript helpers such as defineArticle() and defineProduct(). The helpers provide input types and apply node-specific defaults, URL resolution, and relationships. They do not validate your data against Schema.org or Google's structured data requirements, so test the rendered output before deploying it.
Quick Start
import { defineArticle, useSchemaOrg } from '@unhead/schema-org'
// Generates an Article node and resolves its image and publication date
useSchemaOrg(unheadInstance, [
defineArticle({
headline: 'My Blog Post',
image: '/images/post.jpg',
datePublished: new Date(),
})
])
Background
Unhead Schema.org adds a Schema.org graph to your page. Its helper functions cover nodes used by Google's structured data features.
For supported nodes, the graph resolver applies type-specific transforms such as filling defaults, resolving relative URLs, and connecting related nodes. These transforms do not guarantee that the result is eligible for a Google search feature.
You can also provide custom nodes without a node-specific resolver. The graph still assigns a generated @id when one is omitted and performs normal graph serialization.
Scope
The fields documented by Unhead's define* helpers are a Google-focused subset of Schema.org, together with fields used by Unhead's defaults and relationship resolvers. They are not complete TypeScript definitions of each Schema.org type.
Valid properties outside that subset are preserved in the generated JSON-LD:
defineCourse({
name: 'Advanced TypeScript',
description: 'Advanced TypeScript concepts and patterns.',
coursePrerequisites: 'Basic TypeScript',
})
Use a custom node with schema-dts when you need autocomplete for the full Schema.org vocabulary.
Schema.org defines a broad vocabulary, while Google supports a smaller set of types and properties for Search features. Use Google Search Central's feature documentation as the source of truth for Google eligibility.
Page metadata
When resolving the graph, Unhead reads site and page metadata so you do not have to repeat it in every node.
For example, if you have a <title> on your page, Unhead can use the same title as the Schema.org WebPage's name.
Unhead can infer these values from your <head> data:
inLanguage:<html lang="en">(en)title:<title>test</title>(test)description:<meta name="description" content="test">(test)host:<link rel="canonical" href="https://example.com/my-page">(https://example.com)image:<meta property="og:image" content="https://example.com/image.jpg">(https://example.com/image.jpg)
You can supply any missing values through Schema.org Params.
Node deduplication
Some helpers assign a stable default @id. For example, defineWebPage() uses ${canonicalUrl}#webpage, so multiple definitions of the primary WebPage resolve to the same node.
Unhead deduplicates nodes by @id when it resolves the graph.
Value transforms
The package includes resolvers that reduce the work required to maintain structured data.
@unhead/schema-org/@framework is a placeholder. Replace @framework with your framework: vue, react, etc.URL Transformer
Resolver-backed URL fields accept relative links. Depending on the field, the link is resolved against either the configured host or the current page URL.
import { defineComment } from '@unhead/schema-org'
defineComment({
text: 'The setup guide answered my question.',
author: {
name: 'Harlan Wilton',
url: '/user/harlan-wilton',
}
})
[
{
"@id": "https://example.com/#/schema/person/1",
"@type": "Person",
"name": "Harlan Wilton",
"url": "https://example.com/user/harlan-wilton"
},
{
"@id": "https://example.com/#/schema/comment/1",
"@type": "Comment",
"author": {
"@id": "https://example.com/#/schema/person/1"
},
"text": "The setup guide answered my question."
}
]
Image Transformer
Uses the same relative link logic as the URL transformer.
A string image is transformed into an ImageObject, added as a root node, and referenced by its @id.
import { defineArticle } from '@unhead/schema-org'
defineArticle({
image: '/my-image.png',
})
{
"@id": "https://example.com/#/schema/image/1",
"@type": "ImageObject",
"contentUrl": "https://example.com/my-image.png",
"url": "https://example.com/my-image.png"
}
ID Transformer
Providing an @id for a schema node is useful when setting up your own relationships. You can use an absolute URL, a root-relative path containing a fragment, or a short identifier.
Absolute IDs are preserved. Root-relative IDs are resolved against the configured host. A short identifier such as #subbreadcrumb is placed under the helper's generated schema path.
import { defineBreadcrumb } from '@unhead/schema-org'
defineBreadcrumb({
'@id': '#subbreadcrumb',
'itemListElement': [
{ name: 'Sub breadcrumb link', item: '/blog/test' },
],
})
{
"@id": "https://example.com/#/schema/breadcrumb-list/#subbreadcrumb",
"@type": "BreadcrumbList"
}
Type Transformer
Helpers that support subtypes augment a specific @type with the helper's base type. For example, defineWebPage() turns FAQPage into ['WebPage', 'FAQPage'].
import { defineWebPage } from '@unhead/schema-org'
defineWebPage({
'@type': 'FAQPage',
})
{
"@type": [
"WebPage",
"FAQPage"
]
}
Date Transformer
Supported date fields accept a string or a JavaScript Date object. A Date object is serialized in the
ISO 8601 format produced by Date.toISOString().
import { defineWebPage } from '@unhead/schema-org'
defineWebPage({
datePublished: new Date('2022-02-10T00:00:00.000Z'),
})
{
"datePublished": "2022-02-10T00:00:00.000Z"
}
Node relationships
Unhead connects resolver-backed nodes through @id references:
Organization or Person (site identity)
└── WebSite (published by the identity)
└── WebPage (part of the WebSite)
├── Article / Product / etc. (page content)
└── BreadcrumbList (navigation path)
For example, these nodes resolve into the relationships shown above:
useSchemaOrg(unheadInstance, [
defineWebSite({ name: 'My Blog' }), // Root node
defineWebPage({ name: 'About Us' }), // Linked to WebSite
defineArticle({ headline: 'My Post' }), // Linked to WebPage
])
Testing Your Schema
Validate the rendered markup before deploying:
1. Google Rich Results Test
URL: search.google.com/test/rich-results
Checks markup for the structured data features supported by Google and reports:
- Detected rich-result types
- Missing required fields
- Warnings about recommended fields
2. Schema.org Validator
URL: validator.schema.org
Checks general Schema.org syntax and reports:
- Syntax errors in JSON-LD
- Type mismatches
- Unknown properties
Neither tool verifies that the structured data matches the visible page. Google requires markup to describe the page it appears on and does not guarantee a rich result even when the test passes; see the general structured data guidelines.
How Rich Results Appear in Google
Eligible markup may appear in Google with details such as:
| Schema Type | Rich Result |
|---|---|
Article | Title text, image, and date information |
Product | Price, availability, star ratings |
Recipe | Cook time, ratings, calorie count |
Event | Date, location, ticket availability |
BreadcrumbList | Navigation path shown below title |