Skip to content

Schema Markup

Structured data tells Google exactly what a page is about. It powers rich results (star ratings, FAQ accordions, breadcrumbs).


LocalBusiness + ProfessionalService in Layout.astro. See Global Layout & SEO for the full template.

Key types to set correctly:

"@type": ["LocalBusiness", "ProfessionalService"]
// or for a restaurant:
"@type": ["LocalBusiness", "Restaurant"]
// or for a travel agency:
"@type": ["LocalBusiness", "TravelAgency"]

Full type list - pick the most specific subtype available.


Enables Google’s FAQ accordion in search results. Requires 5+ questions.

const faqSchema = {
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: [
{
"@type": "Question",
name: "How long does a website take?",
acceptedAnswer: {
"@type": "Answer",
text: "Most projects go live within 10-14 days of receiving all content.",
},
},
// ... 4+ more
],
};

Pass via the head slot:

<script slot="head" is:inline type="application/ld+json" set:html={JSON.stringify(faqSchema)} />

Already in the global LocalBusiness schema. Must use real numbers:

aggregateRating: {
"@type": "AggregateRating",
ratingValue: "4.9", // actual average
reviewCount: "38", // actual count
bestRating: "5",
worstRating: "1",
}

Blog posts - FAQPage schema via frontmatter

Section titled “Blog posts - FAQPage schema via frontmatter”

Add a faqs array to a post’s frontmatter and the [slug].astro template injects FAQPage JSON-LD automatically. This enables Google FAQ accordion rich results on individual blog posts.

Frontmatter:

faqs:
- q: How long does a website take to build?
a: Most projects go live within 10-14 days of receiving all content.
- q: What does it cost?
a: Starting from ₹15,000 for a basic business website.

In [slug].astro:

const faqs = post.data.faqs ?? [];
const faqSchema = faqs.length ? {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: faqs.map((f: { q: string; a: string }) => ({
'@type': 'Question',
name: f.q,
acceptedAnswer: { '@type': 'Answer', text: f.a },
})),
} : null;
{faqSchema && <script slot="head" is:inline type="application/ld+json" set:html={JSON.stringify(faqSchema)} />}

Aim for 4-6 questions per post. Validate at Google’s Rich Results Test.


Add to individual blog post pages:

const articleSchema = {
"@context": "https://schema.org",
"@type": "Article",
headline: post.data.title,
description: post.data.description,
datePublished: post.data.pubDate.toISOString(),
author: {
"@type": "Organization",
name: "Juju Alpha",
url: "https://jujualpha.in",
},
};

Use Google’s Rich Results Test after deploying to confirm the schema is valid and eligible for rich results.

Common validation errors:

  • aggregateRating.reviewCount must be a number (not a string in some validators - test both)
  • telephone must include country code: +91XXXXXXXXXX
  • url must be the full production URL with https://