Structured Data (Schema.org JSON-LD) - Complete Guide
Overview
Structured data helps search engines understand your content better, potentially leading to rich results in search engine results pages (SERPs). This guide covers implementation across the Baldr ecosystem.
New Feature: Organization Reference Pattern - Define your organization once on the home page and reference it from other pages.
What is Schema.org JSON-LD?
JSON-LD (JavaScript Object Notation for Linked Data) is a method of encoding structured data using JSON. It's recommended by Google and other search engines.
Implementation Locations
1. Backend (BaldrTs)
- Model:
src/models/schemas/seo.schema.ts - Interface:
src/interfaces/page.interface.ts - Storage: MongoDB field
seo.structuredData
2. Back Office (Baldr-Bo)
- Form:
app/components/organisms/modules/seo/pageFormSeo.organism.tsx - Utility:
app/utils/seo/meta.ts - Schema:
app/schemas/page.schema.ts
3. Frontend (baldr-template)
- Hook:
app/hooks/useStructuredData.ts- Custom hook to inject structured data into document head - Component:
app/components/StructuredData.tsx- React component for rendering structured data - Templates:
app/utils/meta.util.ts- Helper functions for common schema types - Usage: Structured data is automatically injected when pages use the
useStructuredDatahook
Common Schema Types & Examples
1. Organization (Homepage)
Best for: Company homepage, about pages
Note: When using the Organization Reference Pattern, you only need to store the organization data without the
@idfield in the database. The system automatically adds the@idand creates references from other pages.
What to store in database (Baldr-Bo):
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Your Company Name",
"url": "https://yourwebsite.com",
"logo": "https://yourwebsite.com/logo.png",
"description": "Brief description of your company",
"address": {
"@type": "PostalAddress",
"streetAddress": "123 Main Street",
"addressLocality": "Paris",
"postalCode": "75001",
"addressCountry": "FR"
},
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+33-1-23-45-67-89",
"contactType": "customer service",
"email": "contact@yourwebsite.com",
"availableLanguage": ["French", "English"]
},
"sameAs": [
"https://www.facebook.com/yourcompany",
"https://www.twitter.com/yourcompany",
"https://www.linkedin.com/company/yourcompany"
]
}
What gets rendered in HTML (automatic):
{
"@context": "https://schema.org",
"@type": "Organization",
"@id": "https://yourwebsite.com/#organization",
"name": "Your Company Name",
...
}
2. WebPage (Standard Page)
Best for: General content pages, landing pages
{
"@context": "https://schema.org",
"@type": "WebPage",
"name": "Page Title",
"description": "Page description",
"url": "https://yourwebsite.com/page",
"inLanguage": "fr-FR",
"datePublished": "2025-01-08T10:00:00+00:00",
"dateModified": "2025-01-08T10:00:00+00:00",
"breadcrumb": {
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://yourwebsite.com"
},
{
"@type": "ListItem",
"position": 2,
"name": "Category",
"item": "https://yourwebsite.com/category"
},
{
"@type": "ListItem",
"position": 3,
"name": "Page Title"
}
]
}
}
3. Article (Blog Post / News)
Best for: Blog articles, news posts, editorial content
Note: When using the Organization Reference Pattern, the system automatically adds a
publisherreference to your organization. You only need to store the article-specific data.
What to store in database:
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Article Title (Max 110 characters)",
"description": "Brief summary of the article",
"image": "https://yourwebsite.com/article-image.jpg",
"datePublished": "2025-01-08T10:00:00+00:00",
"dateModified": "2025-01-08T15:30:00+00:00",
"author": {
"@type": "Person",
"name": "John Doe"
},
"articleSection": "Technology",
"keywords": ["keyword1", "keyword2", "keyword3"]
}
What gets rendered (automatic):
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Article Title",
"publisher": {
"@id": "https://yourwebsite.com/#organization"
},
...
}
4. Product (E-commerce)
Best for: Product pages, e-commerce items
Note: When using the Organization Reference Pattern, the system automatically adds a
providerreference to your organization.
What to store in database:
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Product Name",
"description": "Detailed product description",
"image": [
"https://yourwebsite.com/product-image-1.jpg",
"https://yourwebsite.com/product-image-2.jpg"
],
"brand": {
"@type": "Brand",
"name": "Brand Name"
},
"sku": "PROD-12345",
"offers": {
"@type": "Offer",
"price": "99.99",
"priceCurrency": "EUR",
"availability": "https://schema.org/InStock"
}
}
What gets rendered (automatic):
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Product Name",
"provider": {
"@id": "https://yourwebsite.com/#organization"
},
...
}
5. BreadcrumbList (Navigation)
Best for: All pages (improves navigation understanding)
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://yourwebsite.com"
},
{
"@type": "ListItem",
"position": 2,
"name": "Products",
"item": "https://yourwebsite.com/products"
},
{
"@type": "ListItem",
"position": 3,
"name": "Product Name"
}
]
}
6. FAQPage (FAQ Section)
Best for: FAQ pages, Q&A sections
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is your return policy?",
"acceptedAnswer": {
"@type": "Answer",
"text": "We accept returns within 30 days of purchase for a full refund."
}
},
{
"@type": "Question",
"name": "How long does shipping take?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Standard shipping takes 3-5 business days. Express shipping is available for next-day delivery."
}
}
]
}
7. LocalBusiness (Physical Location)
Best for: Stores, restaurants, service locations
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "Your Business Name",
"image": "https://yourwebsite.com/storefront.jpg",
"address": {
"@type": "PostalAddress",
"streetAddress": "123 Main Street",
"addressLocality": "Paris",
"addressRegion": "Île-de-France",
"postalCode": "75001",
"addressCountry": "FR"
},
"geo": {
"@type": "GeoCoordinates",
"latitude": 48.8566,
"longitude": 2.3522
},
"url": "https://yourwebsite.com",
"telephone": "+33-1-23-45-67-89",
"priceRange": "€€",
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
"opens": "09:00",
"closes": "18:00"
},
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": "Saturday",
"opens": "10:00",
"closes": "16:00"
}
]
}
8. Event
Best for: Events, conferences, webinars
{
"@context": "https://schema.org",
"@type": "Event",
"name": "Event Name",
"description": "Event description",
"startDate": "2025-06-15T19:00:00+02:00",
"endDate": "2025-06-15T23:00:00+02:00",
"eventStatus": "https://schema.org/EventScheduled",
"eventAttendanceMode": "https://schema.org/OfflineEventAttendanceMode",
"location": {
"@type": "Place",
"name": "Venue Name",
"address": {
"@type": "PostalAddress",
"streetAddress": "123 Main Street",
"addressLocality": "Paris",
"postalCode": "75001",
"addressCountry": "FR"
}
},
"image": "https://yourwebsite.com/event-image.jpg",
"organizer": {
"@type": "Organization",
"name": "Your Company",
"url": "https://yourwebsite.com"
},
"offers": {
"@type": "Offer",
"url": "https://yourwebsite.com/event/tickets",
"price": "30",
"priceCurrency": "EUR",
"availability": "https://schema.org/InStock",
"validFrom": "2025-01-01T00:00:00+00:00"
}
}
9. VideoObject
Best for: Video content pages
{
"@context": "https://schema.org",
"@type": "VideoObject",
"name": "Video Title",
"description": "Video description",
"thumbnailUrl": "https://yourwebsite.com/video-thumbnail.jpg",
"uploadDate": "2025-01-08T10:00:00+00:00",
"duration": "PT10M30S",
"contentUrl": "https://yourwebsite.com/videos/video.mp4",
"embedUrl": "https://yourwebsite.com/embed/video",
"publisher": {
"@type": "Organization",
"name": "Your Company",
"logo": {
"@type": "ImageObject",
"url": "https://yourwebsite.com/logo.png"
}
}
}
Usage in Baldr Projects
Backend (BaldrTs)
The structured data is stored in the seo.structuredData field:
// Creating a page with structured data
const page = await Page.create({
title: "My Product Page",
path: "/products/my-product",
seo: {
metaTitle: "My Product | Your Store",
metaDescription: "Amazing product description",
structuredData: {
"@context": "https://schema.org",
"@type": "Product",
"name": "My Product",
"description": "Amazing product",
// ... more fields
}
}
});
Back Office (Baldr-Bo)
Use the SEO form in the page editor:
- Navigate to Pages module
- Create or edit a page
- Go to the SEO tab
- Scroll to "Données structurées (Schema.org JSON-LD)"
- Paste your JSON-LD code
The form will validate the JSON and save it to the database.
Frontend (baldr-template)
The structured data is automatically injected into the document head using the useStructuredData hook:
// In route file (e.g., routes/_index.tsx or routes/$.tsx)
import { useStructuredData } from "~/hooks/useStructuredData";
export default function MyPage({ loaderData }: Route.ComponentProps) {
// This hook injects structured data into document head
useStructuredData(loaderData?.page?.seo?.structuredData);
return <div>Your page content</div>;
}
// The structured data will be rendered as:
// <script type="application/ld+json">
// { "@context": "https://schema.org", ... }
// </script>
Alternative: Using the component directly
import StructuredData from "~/components/StructuredData";
export default function MyPage() {
const structuredData = {
"@context": "https://schema.org",
"@type": "WebPage",
"name": "My Page"
};
return (
<>
<StructuredData data={structuredData} />
<div>Your page content</div>
</>
);
}
Using Utility Templates
Both projects now include helper functions for common schemas:
// baldr-template
import { structuredDataTemplates } from "~/utils/meta.util";
// Create an organization schema
const orgSchema = structuredDataTemplates.organization({
name: "Your Company",
url: "https://yourwebsite.com",
logo: "https://yourwebsite.com/logo.png",
description: "Company description"
});
// Create a product schema
const productSchema = structuredDataTemplates.product({
name: "Product Name",
description: "Product description",
image: "https://yourwebsite.com/product.jpg",
offers: {
price: 99.99,
priceCurrency: "EUR",
availability: "https://schema.org/InStock"
}
});
Best Practices
1. Always Validate
- Use Google's Rich Results Test
- Use Schema.org's Validator
- Check for errors in Google Search Console
2. Be Accurate
- Only use schemas that accurately represent your content
- Don't add fake reviews or misleading information
- Keep data up to date (prices, availability, dates)
3. Use Complete Data
- Include all required properties for your schema type
- Add recommended properties when available
- Provide high-quality images (min 1200x675px for articles)
4. Follow Guidelines
- Read Google's Structured Data Guidelines
- Follow specific guidelines for each schema type
- Avoid spammy practices
5. Common Mistakes to Avoid
- ❌ Adding structured data for content not visible on the page
- ❌ Using incorrect date formats (use ISO 8601: YYYY-MM-DDTHH:MM:SS+TZ)
- ❌ Missing required fields
- ❌ Invalid JSON syntax
- ❌ Using schema types incorrectly
6. Multiple Schemas
You can combine multiple schemas on one page:
[
{
"@context": "https://schema.org",
"@type": "WebPage",
"name": "Page Title"
},
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [...]
}
]
Testing & Validation
Tools
- Google Rich Results Test: https://search.google.com/test/rich-results
- Schema Markup Validator: https://validator.schema.org/
- Google Search Console: Monitor performance and errors
Testing Process
- Add structured data to a page
- Save and publish
- Test with Rich Results Test
- Fix any errors or warnings
- Monitor in Search Console after indexing
Impact on SEO
Structured data can enable:
- Rich Snippets: Enhanced search results with ratings, prices, etc.
- Rich Cards: Visually enhanced mobile results
- Knowledge Graph: Information panels in search results
- Voice Search: Better understanding for voice assistants
- Featured Snippets: Increased chance of appearing in position zero
Resources
- Schema.org Documentation: https://schema.org/docs/schemas.html
- Google Search Central: https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data
- JSON-LD Playground: https://json-ld.org/playground/
- Schema.org Full List: https://schema.org/docs/full.html
Support
For questions or issues:
- Check this documentation first
- Validate your structured data with online tools
- Review Google Search Console for specific errors
- Consult Schema.org documentation for specific types