JSON-LD Schema Markup: Comprehensive SEO Implementation Guide
JSON-LD structured data informs search engines precisely about your content. Proper schema markup enables rich results in Google Search — including FAQ dropdowns, article carousels, breadcrumb trails, and more — shown directly in search listings.
This guide details all key schema types with authentic C# code and exact JSON output, using examples from a live Blazor codebase.

Contents
What JSON-LD is and its importance for SEO
JSON-LD (JavaScript Object Notation for Linked Data) encodes structured data in JSON format. Search engines like Google use this to grasp your content’s meaning beyond keywords.
When Google interprets your structured data, your pages qualify for rich results — enhanced listings showing ratings, FAQ dropdowns, images, breadcrumbs, and more directly in search results. These typically attract more clicks than standard links.
Google advises using JSON-LD rather than Microdata or RDFa, as it can be placed anywhere on the page, including the head, without altering existing HTML. This keeps structured data separate from your markup.
Eligibility for rich results
Correct schema markup qualifies your pages for FAQ dropdowns, article carousels, breadcrumb trails, and other rich features in Google Search.
Increased clicks without ranking change
Clear semantic meaning
Structured data removes uncertainty. A page with Q&A content is marked as a FAQPage, so Google displays it as a FAQ rich result.
Inform search engines precisely about your content
No changes to HTML required
JSON-LD is placed in a script tag within the head, separate from visible HTML, so adding or updating schema won’t disrupt layouts or accessibility.
Clear separation of concerns
JSON-LD compared to Microdata and RDFa
There are three ways to embed schema.org structured data in web pages. Google recognises all, but they vary greatly in application and upkeep.
| Format | Syntax location | Maintenance | SEO impact | Google’s recommendation |
|---|---|---|---|---|
| JSON-LD | Separate script tag | Simple — no HTML edits | Complete rich result compatibility | Recommended |
| Microdata | Inline HTML attributes | High — closely tied to markup | Complete rich result compatibility | Supported |
| RDFa | Inline HTML attributes | High — closely tied to markup | Complete rich result compatibility | Supported |
Why JSON-LD is easier to maintain
Microdata and RDFa scatter schema attributes across your HTML. Template changes can break structured data unnoticed. JSON-LD is self-contained — updating the script won’t affect HTML.
Master contemporary web development with SEO essentials
A tip from me I found this course useful for grasping how technical SEO, structured data, and modern web standards combine in practical projects.
- Discover how to implement HTML meta tags, Open Graph, and JSON-LD structured data.
- Effective SEO techniques to improve search engine visibility and rankings.
- Practical projects focusing on responsive design and optimising performance.
Key schema types and their uses
Schema.org lists hundreds of types, but a few cover most web content. These types enable rich results in Google Search.
| Schema type | Use case | Type of rich result |
|---|---|---|
| Article | Blog posts, guides, news articles | Article carousel, Top stories |
| FAQPage | Pages featuring question and answer pairs | FAQ dropdown in search results |
| BreadcrumbList | Pages with navigation hierarchy | Breadcrumb trail beneath the URL |
| WebSite / WebPage | Homepage, hub pages, landing pages | Sitelinks search box, entity recognition |
| SoftwareApplication | Apps, tools, software products | App rich result showing rating and price |
Schema.org vocabulary
All schema types are defined at schema.org. The @context property in each JSON-LD block instructs parsers to interpret properties using the schema.org vocabulary. Multiple schema types can be combined on one page — Google processes each script separately.
Implementing Article schema
Article schema is vital for content sites. It informs Google of the headline, description, publication date, author, and publisher — the essential properties for rich result eligibility.
The C# class below models serialization. Each property maps directly to the corresponding JSON-LD field via JsonPropertyName attributes.
private class ArticleSchema
{
[JsonPropertyName("@context")]
public string Context { get; } = "https://schema.org";
[JsonPropertyName("@type")]
public string Type { get; } = "Article";
[JsonPropertyName("headline")]
public string? Headline { get; set; }
[JsonPropertyName("description")]
public string? Description { get; set; }
[JsonPropertyName("image")]
public string? Image { get; set; }
[JsonPropertyName("url")]
public string? Url { get; set; }
[JsonPropertyName("author")]
public Organization? Author { get; set; }
[JsonPropertyName("publisher")]
public ArticlePublisher? Publisher { get; set; }
[JsonPropertyName("datePublished")]
public string? DatePublished { get; set; }
[JsonPropertyName("dateModified")]
public string? DateModified { get; set; }
[JsonPropertyName("articleSection")]
public List<string>? ArticleSection { get; set; }
}Required properties include headline, image, datePublished, dateModified, author, and publisher. The articleSection array is optional but advised — it indicates the article’s topical focus to Google.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "JSON-LD Schema Markup: Complete SEO Implementation Guide",
"description": "Learn how to implement JSON-LD structured data for Article, FAQPage, BreadcrumbList, WebSite, and WebPage schema types.",
"image": "https://ghostlyinc.com/images/web/jsonldguide/opengraph/hero-1200.png",
"url": "https://ghostlyinc.com/en/json-ld-schema-markup-seo-guide/",
"author": {
"@type": "Organization",
"name": "GhostlyInc",
"url": "https://ghostlyinc.com"
},
"publisher": {
"@type": "Organization",
"name": "GhostlyInc",
"logo": {
"@type": "ImageObject",
"url": "https://ghostlyinc.com/images/logo.png"
}
},
"datePublished": "2026-03-28T10:00:00Z",
"dateModified": "2026-03-28T10:00:00Z",
"articleSection": [
"What is JSON-LD and why it matters for SEO",
"JSON-LD vs. Microdata vs. RDFa",
"Core schema types and when to use them",
"Article schema implementation"
]
}
</script>Both author and publisher are typed as Organization. For personal blogs, the author may be a Person with a name and URL.
FAQ schema for rich snippets
FAQPage schema generates FAQ rich results — expandable Q&A pairs shown directly in Google Search below your listing. This can greatly increase vertical space, boosting visibility and click-through rates.
The FaqPage class contains a list of question entities. Each must have a name (the question) and an acceptedAnswer with a text property (the answer).
private class FaqPage
{
[JsonPropertyName("@context")]
public string Context { get; } = "https://schema.org";
[JsonPropertyName("@type")]
public string Type { get; } = "FAQPage";
[JsonPropertyName("@id")]
public string? Id { get; set; }
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("mainEntity")]
public List<FaqEntity>? MainEntity { get; set; }
}
private class FaqEntity
{
[JsonPropertyName("@type")]
public string Type { get; } = "Question";
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("acceptedAnswer")]
public FaqAnswer? AcceptedAnswer { get; set; }
}
private class FaqAnswer
{
[JsonPropertyName("@type")]
public string Type { get; } = "Answer";
[JsonPropertyName("text")]
public string? Text { get; set; }
}The output is a single FAQPage block with a mainEntity array. Each item is a Question type with an acceptedAnswer. Google supports up to ten questions per page for rich results.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"@id": "https://ghostlyinc.com/en/json-ld-schema-markup-seo-guide/#faq",
"name": "Frequently asked questions",
"mainEntity": [
{
"@type": "Question",
"name": "What is the difference between JSON-LD and Microdata?",
"acceptedAnswer": {
"@type": "Answer",
"text": "JSON-LD is a separate script block that lives in the head and does not touch HTML. Microdata adds attributes directly to HTML elements. Google recommends JSON-LD for its maintainability."
}
},
{
"@type": "Question",
"name": "How many FAQ questions can I mark up?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Google supports up to ten questions per page for the FAQ rich result. Additional questions are still valid schema but will not appear in the search result enhancement."
}
}
]
}
</script>The @id on the FAQPage block anchors the schema to a specific URL fragment. This best practice helps parsers clearly identify each entity on pages with multiple schema blocks.
WebSite and WebPage schema
WebSite and WebPage schema form the core entity graph for a site. WebSite identifies the site — its name, URL, language, and publisher. WebPage describes the page and links it to the WebSite via isPartOf.
Both classes use the same JSON-LD pattern. The @id on WebSite is the domain root; on WebPage it is the full page URL.
private class WebSiteSchema
{
[JsonPropertyName("@context")]
public string Context { get; } = "https://schema.org";
[JsonPropertyName("@type")]
public string Type { get; } = "WebSite";
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("url")]
public string? Url { get; set; }
[JsonPropertyName("inLanguage")]
public string? InLanguage { get; set; }
[JsonPropertyName("publisher")]
public Organization? Publisher { get; set; }
}
private class WebPageSchema
{
[JsonPropertyName("@context")]
public string Context { get; } = "https://schema.org";
[JsonPropertyName("@type")]
public string Type { get; } = "WebPage";
[JsonPropertyName("@id")]
public string? Id { get; set; }
[JsonPropertyName("name")]
public string? Name { get; set; }
[JsonPropertyName("description")]
public string? Description { get; set; }
[JsonPropertyName("url")]
public string? Url { get; set; }
[JsonPropertyName("inLanguage")]
public string? InLanguage { get; set; }
[JsonPropertyName("isPartOf")]
public WebSiteReference? IsPartOf { get; set; }
}The inLanguage property uses BCP 47 codes (e.g. en, de, fr). The isPartOf link connects the WebPage to the WebSite entity by referencing the domain’s @id, aiding Google in building a full entity model.
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "GhostlyInc",
"url": "https://ghostlyinc.com",
"inLanguage": "en",
"publisher": {
"@type": "Organization",
"name": "GhostlyInc",
"url": "https://ghostlyinc.com"
}
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebPage",
"@id": "https://ghostlyinc.com/en/json-ld-schema-markup-seo-guide/",
"name": "JSON-LD Schema Markup: Complete SEO Implementation Guide",
"description": "Learn how to implement JSON-LD structured data for Article, FAQPage, BreadcrumbList, WebSite, and WebPage schema types.",
"url": "https://ghostlyinc.com/en/json-ld-schema-markup-seo-guide/",
"inLanguage": "en",
"isPartOf": {
"@type": "WebSite",
"@id": "https://ghostlyinc.com"
}
}
</script>Best practices for implementation
The WrapInScriptTag helper method converts JSON strings into valid JSON-LD blocks by wrapping them in a script tag with the application/ld+json MIME type.
All schema builders — Article, FAQPage, BreadcrumbList, WebSite, and WebPage — use this method to pass their serialized JSON to the utility.
private static MarkupString WrapInScriptTag(string json)
{
var builder = new StringBuilder();
builder.AppendLine("<script type=\"application/ld+json\">");
builder.AppendLine(json);
builder.AppendLine("</script>");
return new MarkupString(builder.ToString());
}The SchemaContext object is the entry point for BuildSchema. It holds all data needed to build schema blocks for a page — type, metadata, FAQs, breadcrumbs, and article info.
public SchemaBuildResult BuildSchema(SchemaContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
var jsonLd = new List<MarkupString>();
switch (context.PageType)
{
case PageSchemaType.Home:
jsonLd.Add(WebSite(context));
jsonLd.Add(WebPage(context));
break;
case PageSchemaType.Article:
jsonLd.Add(Article(context.Article!));
break;
case PageSchemaType.Tool:
jsonLd.Add(WebPage(context));
jsonLd.Add(SoftwareApplication(context.SoftwareApplication!));
break;
case PageSchemaType.Hub:
jsonLd.Add(WebPage(context));
break;
}
if (context.Faqs != null && context.Faqs.Count > 0)
{
jsonLd.Add(FAQ(context.Faqs.ToList(), context.FaqTitle, context.Url));
}
if (context.ParentHierarchy.Count > 0)
{
jsonLd.Add(BreadcrumbList(BuildBreadcrumbItems(context)));
}
return new SchemaBuildResult(jsonLd, context.PageType == PageSchemaType.Article);
}The dispatch switch allows composable schema building. FAQs and breadcrumbs are appended if present, regardless of page type, enabling any page to include these without altering core logic.
Testing and validating your schema
Valid JSON-LD syntax alone doesn’t guarantee rich results. Google’s tools verify syntax and whether your content meets policies for each rich result type.
Rich Results Test
Use search.google.com/test/rich-results to test URLs or raw HTML. Google shows detected rich result types and flags missing required properties.
Google’s official eligibility checker
Schema Markup Validator
validator.schema.org validates your markup against schema.org specs independently of Google’s rich result policies. Useful for spotting typos and type errors.
Schema.org syntax validation
Google Search Console
The Enhancements section in Search Console reports schema errors and warnings across your indexed pages. Use it for ongoing monitoring after initial checks.
Monitor at scale after launch