JSON-LD Schema Markup: Complete SEO Implementation Guide
JSON-LD structured data tells search engines exactly what your content is about. The right schema markup unlocks rich results in Google Search — FAQ dropdowns, article carousels, breadcrumb trails, and more — directly from the search results page.
This guide covers every major schema type with real C# implementation code and the exact JSON output it produces. Every example is taken directly from a production Blazor codebase.

Table of Content
What is JSON-LD and why it matters for SEO
JSON-LD (JavaScript Object Notation for Linked Data) is a method of encoding structured data using the JSON format. Search engines such as Google read this data to understand the meaning of your content, not just its keywords.
When Google can parse your structured data it becomes eligible for rich results — visually enhanced search listings that display ratings, FAQ dropdowns, article images, breadcrumb trails, and other features directly in the search results page. Rich results consistently achieve higher click-through rates than plain blue links.
Google officially recommends JSON-LD over Microdata and RDFa because it can be placed anywhere in the page — including the head — and does not require modifying existing HTML elements. The structured data is completely decoupled from your markup.
Rich result eligibility
Valid schema markup makes your pages eligible for FAQ dropdowns, article carousels, breadcrumb trails, and other rich features in Google Search.
More clicks from the same ranking
Semantic clarity
Structured data removes ambiguity. A page about a question-and-answer topic is explicitly declared as a FAQPage, so Google knows to render it as a FAQ rich result.
Tell search engines exactly what you have
Zero HTML changes
JSON-LD lives in a script tag in the head. It never touches your visual HTML, so adding or updating schema never risks breaking layouts or accessibility.
Clean separation of concerns
JSON-LD vs. Microdata vs. RDFa
Three formats exist for embedding schema.org structured data in web pages. All three are understood by Google, but they differ significantly in how they are applied and maintained.
| Format | Syntax location | Maintenance | SEO impact | Google recommendation |
|---|---|---|---|---|
| JSON-LD | Separate script tag | Easy — no HTML changes | Full rich result support | Recommended |
| Microdata | Inline HTML attributes | High — tightly coupled to markup | Full rich result support | Supported |
| RDFa | Inline HTML attributes | High — tightly coupled to markup | Full rich result support | Supported |
Why JSON-LD wins on maintainability
With Microdata and RDFa, schema attributes are scattered throughout your HTML. A design change that restructures a template can silently break structured data. JSON-LD is a self-contained block — update the script once and no HTML is affected.
Master Modern Web Development with SEO Best Practices
Tip from me I found this course valuable for understanding how technical SEO, structured data, and modern web standards work together in real-world projects.
- Learn HTML meta tags, Open Graph, and JSON-LD structured data implementation.
- Practical SEO strategies for better search engine visibility and ranking.
- Hands-on projects covering responsive design and performance optimization.
Core schema types and when to use them
Schema.org defines hundreds of types but a handful cover the majority of web content. These are the types that unlock rich results in Google Search.
| Schema type | Use case | Rich result type |
|---|---|---|
| Article | Blog posts, guides, news articles | Article carousel, Top stories |
| FAQPage | Pages with question/answer pairs | FAQ dropdown in search results |
| BreadcrumbList | Any page with a navigation hierarchy | Breadcrumb trail below the URL |
| WebSite / WebPage | Homepage, hub pages, landing pages | Sitelinks search box, entity recognition |
| SoftwareApplication | Apps, tools, software products | App rich result with rating and price |
Schema.org vocabulary
All schema types are defined at schema.org. The @context property in every JSON-LD block tells parsers to interpret property names against the schema.org vocabulary. You can combine multiple schema types on a single page — Google processes each script block independently.
Article schema implementation
Article schema is the most important type for content-driven sites. It tells Google the headline, description, publication date, author, and publisher of a piece of content — the minimum set of properties required for rich result eligibility.
The C# class below is the serialization model. Each property maps directly to the corresponding JSON-LD field using 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; }
}The required properties are: headline, image, datePublished, dateModified, author, and publisher. The articleSection array is optional but recommended — it signals the article's topical scope 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>The author and publisher are both typed as Organization. For personal blogs, the author can instead be a Person with a name and url.
FAQ schema for rich snippets
FAQPage schema creates FAQ rich results — expandable question/answer pairs displayed directly in Google Search results below your page listing. This can significantly increase the vertical space your result occupies, improving visibility and click-through rates.
The FaqPage class holds a list of question entities. Each entity 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 is best practice for pages that contain multiple schema blocks, as it allows parsers to unambiguously identify each entity.
WebSite and WebPage schema
WebSite and WebPage schema establish the foundational entity graph for a site. WebSite identifies the site itself — its name, URL, language, and publisher. WebPage describes the individual page and links it to the parent WebSite using the isPartOf relationship.
Both classes follow the same JSON-LD pattern. The @id on WebSite is the domain root; the @id on WebPage 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 language codes (e.g. en, de, fr). The isPartOf link ties the WebPage to the WebSite entity by referencing the domain's @id. This helps Google build a complete entity model of your site.
<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>Implementation best practices
The WrapInScriptTag helper method is the single point where JSON strings become valid JSON-LD blocks. It wraps any serialized schema payload in the required script tag with the application/ld+json MIME type.
This is the method that all schema builders in the service call — Article, FAQPage, BreadcrumbList, WebSite, and WebPage all pass their serialized JSON to this same 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 the BuildSchema method. It carries all the data needed to build the full set of schema blocks for a page — type, metadata, FAQ list, breadcrumb hierarchy, and article data.
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 makes the schema builder composable. FAQs and breadcrumbs are always appended if present, regardless of page type. This means any page type can have a FAQ block or breadcrumb trail added without changing the core dispatch logic.
Testing and validating your schema
Valid JSON-LD syntax does not guarantee rich result eligibility. Google's tools check both syntax validity and whether your content meets the policy requirements for each rich result type.
Rich Results Test
Use search.google.com/test/rich-results to test any URL or paste raw HTML. Google confirms which rich result types were detected and highlights any missing required properties.
Google's official eligibility checker
Schema Markup Validator
validator.schema.org checks your markup against the schema.org specification independently of Google's rich result policies. Useful for catching property name typos and type mismatches.
Schema.org syntax validation
Google Search Console
The Enhancements section in Search Console reports schema errors and warnings at scale across your indexed pages. Use it for ongoing monitoring after initial validation.
Monitor at scale post-launch