Schema.org
Learn how to use Schema.org in Next.js with Prismic.
Schema.org metadata tells search engines how to understand the content of your website so they can generate rich, interactive search results for your website. The search engines will typically prioritize these results over standard ones.
If you run a news website, for example, you can define article titles, summaries, and photos. Or if your website contains restaurant locations, you can provide restaurant hours, addresses, and menus.
Schema.org defines standardized sets of attributes for almost any kind of metadata you want to share with search engines.
This guide demonstrates a few kinds of schemas to show how you can connect your website’s content to whichever schema you need.
Find a specific schema definition using Schema.org’s full list of schemas.
General content modeling strategy
Much of the content needed by search engines already exists in your content models. Fields for a blog post’s title and author, for example, are likely already included. This content can be used in both the visual parts of your website and the invisible metadata.
Any metadata fields that don’t exist will need to be added. When necessary, fields can be labeled with “(Schema.org)” to let content writers know which field values won’t be visible on your website.
JSDoc and TypeScript
Metadata must be written using specific attribute names. Google’s schema-dts
can be used with JSDoc or TypeScript to more accurately write schemas. Using the package gives you auto-completion in your code editor and verifies you are passing the correct data.
Install schema-dts
with the following command:
npm install --save-dev schema-dts
The examples below use schema-dts
with JSDoc @type
comments.
Example: Article
The Article schema defines an article from a news publication, a blog, or anything that publishes dated write-ups.
Modeling article metadata
The following fields are needed to provide article metadata:
- Static Zone
- Title
title
Rich Text - UID
uid
UID - Author
author
Content Relationship - Publication Date
publication_date
Date - Featured Image
featured_image
Image
Rendering article metadata
Article metadata can be queried and rendered like the following page. Note the use of next/head
to add the Schema.org metadata to the page’s <head>
.
import Head from "next/head";
import * as prismic from "@prismicio/client";
import { createClient } from "../../prismicio";
/** @param {import("next").InferGetStaticPropsType<typeof getStaticProps>} */
export default function Page({ article }) {
/** @type {import('schema-dts').Article} */
const schema = {
"@context": "https://schema.org",
"@type": "Article",
headline: prismic.asText(article.data.title),
author: {
"@type": "Person",
name: prismic.asText(article.data.author.data.name),
// The full URL must be provided, including the website's domain.
url: new URL(
prismic.asLink(article.data.author),
"https://example.com",
),
},
image: prismic.asImageSrc(article.data.featured_image),
datePublished: article.data.publication_date,
dateModified: article.last_publication_date,
};
return (
<div>
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(schema),
}}
/>
</Head>
<main>
<p>
The following schema has been added to the{" "}
<code><head></code> of this page:
</p>
<pre>
<code>{JSON.stringify(schema, null, 4)}</code>
</pre>
</main>
</div>
);
}
/** @param {import("next").GetStaticPropsContext<{ uid: string }>} */
export async function getStaticProps({
previewData,
params,
}) {
const client = createClient({ previewData });
const article = await client.getByUID(
"article",
params.uid,
{
fetchLinks: ["author.name"],
},
);
return {
props: { article },
};
}
/** @type {import("next").GetStaticPaths} */
export async function getStaticPaths() {
const client = createClient();
const articles = await client.getAllByType("article");
return {
paths: articles.map((article) =>
prismic.asLink(article),
),
fallback: false,
};
}
Example: Event
The Event schema defines a date, time, location, and more for an event.
Modeling event metadata
The following fields are needed to provide event metadata:
- Static Zone
- Name
name
Rich Text - UID
uid
UID - Description
description
Key Text - Start Date
start_date
Timestamp - End Date
end_date
Timestamp
Rendering event metadata
Event metadata can be queried and rendered like the following page. Note the use of next/head
to add the Schema.org metadata to the page’s <head>
.
import Head from "next/head";
import * as prismic from "@prismicio/client";
import { createClient } from "../../prismicio";
/** @param {import("next").InferGetStaticPropsType<typeof getStaticProps>} */
export default function Page({ event }) {
/** @type {import('schema-dts').Event} */
const schema = {
"@context": "https://schema.org",
"@type": "Event",
name: prismic.asText(event.data.name),
description: event.data.description,
startDate: event.data.start_date,
endDate: event.data.end_date,
};
return (
<div>
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(schema),
}}
/>
</Head>
<main>
<p>
The following schema has been added to the{" "}
<code><head></code> of this page:
</p>
<pre>
<code>{JSON.stringify(schema, null, 4)}</code>
</pre>
</main>
</div>
);
}
/** @param {import("next").GetStaticPropsContext<{ uid: string }>} */
export async function getStaticProps({
previewData,
params,
}) {
const client = createClient({ previewData });
const event = await client.getByUID("event", params.uid);
return {
props: { event },
};
}
/** @type {import("next").GetStaticPaths} */
export async function getStaticPaths() {
const client = createClient();
const events = await client.getAllByType("event");
return {
paths: events.map((event) => prismic.asLink(event)),
fallback: false,
};
}
Example: FAQ
The FAQ schema defines a set of questions and answers typically shown on a Frequently Asked Questions page.
Modeling FAQ metadata
The following fields are needed to provide FAQ metadata:
- Static Zone
- UID
uid
UID - Title
title
Rich TextTitle for the FAQs
- Questions
questions
Group- Question
question
Rich Text - Answer
answer
Rich Text
Rendering FAQ metadata
FAQ metadata can be queried and rendered like the following page. Note the use of next/head
to add the Schema.org metadata to the page’s <head>
.
import Head from "next/head";
import * as prismic from "@prismicio/client";
import { createClient } from "../../prismicio";
/** @param {import("next").InferGetStaticPropsType<typeof getStaticProps>} */
export default function Page({ faqs }) {
/** @type {import('schema-dts').FAQPage} */
const schema = {
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: faqs.data.questions.map((question) => ({
"@type": "Question",
name: prismic.asText(question.question),
acceptedAnswer: prismic.asHTML(question.answer),
})),
};
return (
<div>
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(schema),
}}
/>
</Head>
<main>
<p>
The following schema has been added to the{" "}
<code><head></code> of this page:
</p>
<pre>
<code>{JSON.stringify(schema, null, 4)}</code>
</pre>
</main>
</div>
);
}
/** @param {import("next").GetStaticPropsContext<{ uid: string }>} */
export async function getStaticProps({
previewData,
params,
}) {
const client = createClient({ previewData });
const faqs = await client.getByUID("faqs", params.uid);
return {
props: { faqs },
};
}
/** @type {import("next").GetStaticPaths} */
export async function getStaticPaths() {
const client = createClient();
const faqs = await client.getAllByType("faqs");
return {
paths: faqs.map((faq) => prismic.asLink(faq)),
fallback: false,
};
}
More examples
See Google’s Search Central documentation for a collection of Schema.org guides.
Although Google’s examples are not Prismic-specific, the examples’ JSON should help you determine which Prismic fields are required.