Add Structured Data To Your Svelte App
| Published: March 02, 2024
| Updated: March 02, 2024
Structured data is a massively underutilized weapon for improving search engine rankings and helping them understand your content better. And for most Svelte applications, developers overlook this opportunity.
Understanding the “when”, “where” and “how” of structured data when it comes to your website isn’t super straightforward, but if you do it right the results will pay dividends.
Google themselves have even written case studies on how businesses have massively increased organic traffic since adopting structured data.
This article will walk you through the process of adding relevant structured data to your Svelte website, and provide code snippets to get you going quickly.
What does structured data look like in the search results
If you’ve ever used Google, you’ve seen rich results pulling from structured data - they are the results that are more than the standard “title and description”:
❌ Standard Search Result
✔️ Rich Search Result with Structured Data
As you can see, the rich result is more engaging and takes up more real-estate on the page.
Whilst this is just an example of one rich result (a Question-Answer schema), there are 35 schemas recognized by Google which may be more relevant to your app.
So let’s find schemas related to your site and integrate the structured data into your app.
Find Relevant Schemas
The first step of integrating structured data into your app is which type/s to use. You should peruse Google’s official Structured Markup Page to find options you believe would help search engines understand your content better.
You may select more than one type of structured data to add to your pages, so long as they are all relevant.
Don’t use structured markup that isn’t relevant - Google may apply manual actions if you misuse this feature or violate their content or spam policies.
Seeing as there are so many different schema types, we’ll focus on the process of adding a schema to your page, rather than just copy-pasting the code. This is so that you can fundamentally understand schemas and apply the steps to any structured data you choose.
Read the schema specification
Once you’ve selected the structured data type from the official supported schemas page, click on it to observe the specification.
In this example, we’re going to add the FAQ structured data to our page. If all goes to plan and Google recognizes it as valid, our page may be eligible to show a rich result that looks like this:
Go to the examples section, and select the JSON-LD
code - this is what we’ll be using for all of our structured data code moving forward.
Copy the <script>
tag part of the JSON-LD
example, which should look like this:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [{
"@type": "Question",
"name": "How to find an apprenticeship?",
"acceptedAnswer": {
"@type": "Answer",
"text": "<p>We provide an official service to search through available apprenticeships. To get started, create an account here, specify the desired region, and your preferences. You will be able to search through all officially registered open apprenticeships.</p>"
}
}, {
"@type": "Question",
"name": "Whom to contact?",
"acceptedAnswer": {
"@type": "Answer",
"text": "You can contact the apprenticeship office through our official phone hotline above, or with the web-form below. We generally respond to written requests within 7-10 days."
}
}]
}
</script>
In Svelte, we can’t just paste this directly into our code and be done with it - we’ll have to make a few changes to have it work on our page.
Adding structured data to your Svelte App
In the step above, we were able to locate the shape of the structured data we chose (in our case, an FAQ).
To add this to our Svelte page, you must wrap the JSON-LD <script>
and its contents inside a template literal and within a {@html}
special tag and place it in the page’s markup.
Which will look like this:
+page.svelte
<script>
// script contents...
</script>
{@html `<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [{
"@type": "Question",
"name": "How to find an apprenticeship?",
"acceptedAnswer": {
"@type": "Answer",
"text": "<p>We provide an official service to search through available apprenticeships. To get started, create an account here, specify the desired region, and your preferences. You will be able to search through all officially registered open apprenticeships.</p>"
}
}, {
"@type": "Question",
"name": "Whom to contact?",
"acceptedAnswer": {
"@type": "Answer",
"text": "You can contact the apprenticeship office through our official phone hotline above, or with the web-form below. We generally respond to written requests within 7-10 days."
}
}]
}
</script>`}
<!-- Rest of page markup... -->
Remember, you can’t put this within your page <script>
tag - it must be within the Svelte markup.
Obviously you will have to change the Question and Answer values to reflect your page, however you can also include more properties to what’s been used in the example. Let’s now look at how to add more valid properties to our structured data.
For the FAQ schema in particular, the guidelines require us to clearly display the FAQ’s on the page as well. So let’s add this to our page:
<script>
// script contents...
</script>
{@html `<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [{
"@type": "Question",
"name": "How to find an apprenticeship?",
"acceptedAnswer": {
"@type": "Answer",
"text": "<p>We provide an official service to search through available apprenticeships. To get started, create an account here, specify the desired region, and your preferences. You will be able to search through all officially registered open apprenticeships.</p>"
}
}, {
"@type": "Question",
"name": "Whom to contact?",
"acceptedAnswer": {
"@type": "Answer",
"text": "You can contact the apprenticeship office through our official phone hotline above, or with the web-form below. We generally respond to written requests within 7-10 days."
}
}]
}
</script>`}
<div>
<h2>Frequently Asked Questions(FAQ)</h2>
<div>
<h3>How to find an apprenticeship?</h3>
<div>
<div>
We provide an official service to search through available apprenticeships. To get started,
create an account here, specify the desired region, and your preferences. You will be able
to search through all officially registered open apprenticeships.
</div>
</div>
</div>
<div>
<h3>Whom to contact?</h3>
<div>
<div>
You can contact the apprenticeship office through our official phone hotline above, or with
the web-form below. We generally respond to written requests within 7-10 days.
</div>
</div>
</div>
</div>
Adding more properties to the schema
The examples shown on the Structured markup page are simply baseline examples. You can add more properties to your structured data object, so long as it falls within the type definitions. How do we find the type definition for our schema though? Let’s take a look.
If you’re happy with the content in the snippet above, skip to the next section where we componentize our snippets.
Finding Schema Type Definitions
For each schema type you find on the Google markup page, there will be a section called “Structured data type definitions”.
You should be able to append
#structured-data-type-definitions
to the end of your URL and it will take you to this section
This section will give you information about where you can find the full type definition on Schema.org.
For example, in our FAQ example, we can find the type definitions section here. In the text, you’ll see the sentence:
The full definition of FAQPage is provided on schema.org.
The link will take you to the specific FAQPage on Schema.org. If you go to the page, you’ll be shown a list of all potential properties you can add to your FAQ schema. The list is exhaustive and mostly unnecessary, so we’ll leave it for now.
So long as you provide the stated “required properties” (which in our case is mainEntity
), your schema will be valid - anything else is optional.
Once you’ve changed the values and tested the validity of your schema, you have successfully added this FAQ structured markup to your page. 🥳
But if you run a website with many pages, it’s better to implement an automated system for adding structured data to your pages.
Let’s look at how to do this now.
Convert structured data to Svelte components
Converting the structured data code block we used to a component means you don’t have to add this to every page/post you make, and your site will be more robust. You’ll save time, and run into less issues.
To do this, we have to convert the object values, and turn them into types, so we know which data to feed into the component.
For example, if we take the FAQ structured data we used above, we can convert the object type to be this:
// Remember this is just a type, not code to add to a component
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": {
"@type": "Question",
"name": "string",
"acceptedAnswer": {
"@type": "Answer",
"text": "string"
}
}[]
}
In this process, we made the following observations:
@context: "https://schema.org"
is constant, so we can leave this,@type: "FAQPage"
is constant, so we can leave this,mainEntity
contains 2 objects that contain the same shape of data, so we take the object type and make it an array ([]
),- Within
mainEntity
@type: "Question"
is constant, so we can leave this,name
is the question string, which will be dynamic - this must be a prop,- Within
acceptedAnswer
:@type: "Answer"
is a constant, so we can leave this,text
is the answer string, which will be dynamic - this must be a prop.
So with this information, we just need to look at the dynamic data to understand what to accepts as props into the component, which is just an object array containing a question
string and answer
string (makes sense, huh 😆).
type faqs = {
question: string;
answer: string;
}[];
So, let’s create our FAQStructuredDataTag.svelte
component.
Building the component
First, we’ll define the expected props:
FAQStructuredDataTag.svelte
<script lang="ts">
export let faqs: {
question: string;
answer: string;
}[];
</script>
Since we’re using a template literal to define the structured data, we don’t have access to the Svelte {#each}
blocks to create the mainEntity
array. So we’ll have to build the full mainEntity
array in our <script>
tag before passing it to the structured data tag:
<script lang="ts">
export let faqs: {
question: string;
answer: string;
}[];
let mappedFaqs = faqs.map((faq, index) => {
return `{
"@type": "Question",
"name": "${faq.question}",
"acceptedAnswer": {
"@type": "Answer",
"text": "${faq.answer}"
}
}`;
});
</script>
And then we can simply place the mappedFaqs
as the value for mainEntity
in our structured data tag:
{@html `<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [${mappedFaqs}]
}
</script>`}
Don’t forget to wrap
mappedFaqs
in array brackets[]
- as it’s an array, these must be present or else the schema will be invalid.
So all together, this is the full component for the FAQ schema:
FAQStructuredDataTag.svelte
<script lang="ts">
export let faqs: {
question: string;
answer: string;
}[];
let mappedFaqs = faqs.map((faq, index) => {
return `{
"@type": "Question",
"name": "${faq.question}",
"acceptedAnswer": {
"@type": "Answer",
"text": "${faq.answer}"
}
}`;
});
</script>
{@html `<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [${mappedFaqs}]
}
</script>`}
So now, if you want valid structured FAQ schema in your page, simply place it in the markup in your +page.svelte
, like this:
<script lang="ts">
// other script content...
export let data; // In your load function, you can build the faqs object array
</script>
<FaqSchema faqs={data.faqs} />
And the component will also be type-safe, so if there’s an error when passing data to the component, the language server/compiler will warn you.
So now you’ve successfully componentized your structured data snippets for Svelte.
Now we want to use these components to automate the generation of structured data through our entire Svelte app. We’ll explain this by walking through a real-world example of this in action.
But first, we need to quickly touch on using multiple schemas for a page.
Stacking Schemas
You’ve probably perused the Google Structured Data Types Page and thought, “hmm 🤔, I could apply a few of these to my pages”. And you would be correct.
Remember the general rule: if it helps search engines understand the page better, it’s worth providing the structured data.
For example, if you test the schema used on this very page, you’ll notice 4 separate schemas:
For every blog post, there will be 4 schemas:
- Organization (hardcoded site-wide),
- BreadcrumbList (programmatically generated with post data),
- Article (programmatically generated with post data),
- FAQ (questions/answers written for each post, with JSON-LD generated from data)
Let’s look at how we apply these multiple schemas to this website.
How SvelteKit.io applies structured data to blog posts
Since the website organization remains constant across all pages on this website, I’ve hardcoded the Organization schema to my root +layout.svelte
file:
src/routes/+layout.svelte
{@html `<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"url": "https://sveltekit.io",
"name": "Sveltekit.io",
"description": "SvelteKit.io is a website dedicated to helping developers learn about Svelte and Sveltekit."
}
</script>`}
Then for the BreadcrumbList and Article schemas, both of these get populated automatically for every blog post using post-specific data.
Firstly, I’ve created a specific component which combines these 2 schema types:
ArticleBreadcrumbStructuredData.svelte
<script lang="ts">
export let title: string;
export let datePublished: string;
export let dateModified: string;
export let image: string | undefined;
</script>
{@html `<script type="application/ld+json">
[{
"@context": "https://schema.org",
"@type": "Article",
"headline": "${title}",
${
image &&
`"image": [
"https://sveltekit.io${image}"
],`
}
"datePublished": "${datePublished}",
"dateModified": "${dateModified}",
"author": [{
"@type": "Person",
"name": "Jack Landon",
"url": "https://sveltekit.io/about"
}]
},
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [{
"@type": "ListItem",
"position": 1,
"name": "Blog",
"item": "https://sveltekit.io/blog"
},{
"@type": "ListItem",
"position": 2,
"name": "${title}"
}]
}
]
</script>`}
Which then gets added to the dynamic src/routes/blog/[slug]/+page.svelte
directory, like this:
src/routes/blog/[slug]/+page.svelte
<script lang="ts">
import ArticleBreadcrumbStructuredData from '$lib/components/ArticleBreadcrumbStructuredData.svelte';
export let data;
</script>
<ArticleBreadcrumbStructuredData
title={data.meta.title}
datePublished={data.meta.datePublished}
dateModified={data.meta.dateModified}
image={data.meta.image}
/>
So then in the page’s load
function, we pull all the necessary post data and then populate the structured data automatically.
In this directory, we also add the FAQStructuredDataTag
component:
src/routes/blog/[slug]/+page.svelte
<script lang="ts">
import FAQStructuredDataTag from '$lib/components/FAQStructuredDataTag.svelte';
import ArticleBreadcrumbStructuredData from '$lib/components/ArticleBreadcrumbStructuredData.svelte';
export let data;
</script>
<ArticleBreadcrumbStructuredData
title={data.meta.title}
datePublished={data.meta.datePublished}
dateModified={data.meta.dateModified}
image={data.meta.image}
/>
{#if data.meta.faqs}
<FAQStructuredDataTag faqs={data.meta.faqs} />
{/if}
It’s a great system, and if your Svelte app has tens, hundreds, or thousands of posts/pages/products etc. then you can easily apply this structured data system to your site to instantly add structured data and upgrade your SEO opportunities on every page.
Vimeo applied a similar system to their site with outstanding results.
Now we’ve applied applied the structured data across our app, it’s important to make sure it’s valid! Let’s look at how to test our pages live, or before we publish them.
Validate your schema
Given how fickle creating structured data can be, it’s important to test that each page has valid structured data. You can do this with the Google Rich Results Test, or the Schema Markup Validator which provides a more fine-grain assessment.
The right panel will break down each of the properties and the entered values. If there’s any errors in your snippet, the compiler will tell you and show you which line the error is on. 🙏
In this instance, I removed a comma after the answer, and the compiler was able to find it.
Nothing is guaranteed
Just because you’ve added structured data to your pages does not guarantee it will be honored. Search engines may deem it invalid, or just simply not show it as a rich result.
This doesn’t mean it’s not worth doing - you may receive some of the SEO benefits even if you don’t get rich search results.
Conclusion
Well done for adding everything. Hopefully you’ve employed the automated system shared in this article. If you have, you won’t need to worry about structured data for the rest of your app’s life, provided no major changes.
In this article, we learned:
- What structured data is,
- How it can improve visibility on search engines and help us rank better,
- How to find relevant schemas to use for our pages,
- How to add structured data to our Svelte pages,
- How to componentize structured data snippets,
- How to systemize and automate structured data generation for all pages in our Svelte app,
- We looked at how this is done on SvelteKit.io
- How to extend our schemas and where to find valid properties to add,
- How to validate our schemas before publishing and on live web pages
If it’s your first time doing this, it can be a little bit challenging, but you’ll be glad you took the time to systemize structured data through your Svelte app.
You can monitor how effective this strategy is in your Google Search Console ”Search Appearance” tab, where it tells you which type of rich snippets your content has been featured in.
Good luck - I wish you plenty of rich search results and for your Svelte app to have a positive reputation with search engines. ❤️