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.

A diagram showing JSON for a Schema.org definition and its accompanying visual representation shown on search engine results. In this example, an event named "Successful Freelancer Shares Their Words of Wisdom" is represented with the Event schema.

Search engines use metadata to show rich search results, such as bookmarking an upcoming event.

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:

ArticlearticleCustom Type
  • Static Zone
    • TitletitleRich Text
    • UIDuidUID
    • AuthorauthorContent Relationship
    • Publication Datepublication_dateDate
    • Featured Imagefeatured_imageImage

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>.

pages/articles/[uid].js
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>&lt;head&gt;</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:

EventeventCustom Type
  • Static Zone
    • NamenameRich Text
    • UIDuidUID
    • DescriptiondescriptionKey Text
    • Start Datestart_dateTimestamp
    • End Dateend_dateTimestamp

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>.

pages/event/[uid].js
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>&lt;head&gt;</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:

FAQsfaqsCustom Type
  • Static Zone
    • UIDuidUID
    • TitletitleRich Text

      Title for the FAQs

    • QuestionsquestionsGroup
      • QuestionquestionRich Text
      • AnsweranswerRich 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>.

pages/faqs/[uid].js
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>&lt;head&gt;</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.