Lesson
8
Generating JSON-LD dynamically
JSON-LD is a powerful way to provide structured data to search engines—fortunately structured data is what Sanity does best.
Log in to mark your progress for each Lesson and Task
JSON-LD data follows structured conventions for many different types of content. All you'll need to do is take content already authored in your documents, and render it into the DOM in the expected format. We already have FAQs as a document type, so it makes sense to start there.
When it comes to FAQs, proper JSON-LD implementation can help your content appear in rich snippets and potentially even surface you near the top of search results just by providing useful information.
By the end of this lesson, you will:
- Generate JSON-LD for FAQs programmatically
- Implement type-safe JSON-LD using Google's
schema-dts
package - Improve your FAQ block from the page builder course
JSON-LD generation can be challenging to get right as it follows a strict structure. Fortunately, Google provides a TypeScript package called schema-dts
that gives you type safety for your structured content.
Let's start by creating a function that transforms your FAQ data into a JSON-LD friendly structure. Back in Create page builder schema types you created a document type schema for FAQs.
Run the following to install the
schema-dts
packageTerminal
npm i schema-dts
Currently in the GROQ query for pages the FAQ block is returning the full document for every reference.
Let's update this to only extract specific fields from the document, as well as the Portable Text in the body
field as a string using the GROQ function pt::text()
Update your GROQ query for pages, to return the answer in plain text
src/sanity/lib/queries.ts
// replace thisfaqs[]->
// with thisfaqs[]->{ _id, title, body, "text": pt::text(body)}
You've updated your queries, so update your types
Terminal
npm run typegen
The JSON-LD markup can be rendered anywhere in the page—it doesn't need to be stored inside the <head>
. So you can add it directly into components where you already have access to the correct data.
In this instance, you're rendering the FAQ content into an accordion in this block, so you can also have it process that same content into the JSON-LD format and add it to the component output.
Update your
FAQs
block to render JSON-LD content in a script tagsrc/components/blocks/FAQs.tsx
// ...all your imports and typesimport { FAQPage, WithContext } from "schema-dts";
const generateFaqData = (faqs: FAQsProps["faqs"]): WithContext<FAQPage> => ({ "@context": "https://schema.org", "@type": "FAQPage", mainEntity: faqs?.map((faq) => ({ "@type": "Question", name: faq.title!, acceptedAnswer: { "@type": "Answer", text: faq.text!, }, })),});
export function FAQs({ _key, title, faqs }: FAQsProps) { const faqData = generateFaqData(faqs);
return ( <section className="container mx-auto flex flex-col gap-8 py-16"> <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqData) }} /> {/* ...the rest of the component */} </section> );}
Notice the most important part of this block, the <script>
tag. This is where you're adding the JSON-LD to the page. This should get you thinking about how you can reuse this pattern across your site.
The FAQ schema covered here is just the tip of the JSON-LD iceberg. The beauty of structured data is that once implemented, it works silently in the background to enhance your search presence.
Some other examples you may want to implement:
The more you lean into structured data, the more benefits you'll experience.
If there's one thing to take away from this whole course, it's that SEO doesn't need to be a complex process. It's about taking your existing data and repurposing it to make it more digestible for your audience and, by extension, for search crawlers.
The future of the web won't be about configuring hundreds of different fields to get the perfect SEO score. Instead, it will focus on finding ways to accelerate content creation and automating the tasks you don't want to do.
It's time to revise everything you've learned in the final lesson!
You have 3 uncompleted tasks in this lesson
0 of 3