Aller au contenu principal

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 useStructuredData hook

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 @id field in the database. The system automatically adds the @id and 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 publisher reference 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 provider reference 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:

  1. Navigate to Pages module
  2. Create or edit a page
  3. Go to the SEO tab
  4. Scroll to "Données structurées (Schema.org JSON-LD)"
  5. 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

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

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

  1. Google Rich Results Test: https://search.google.com/test/rich-results
  2. Schema Markup Validator: https://validator.schema.org/
  3. Google Search Console: Monitor performance and errors

Testing Process

  1. Add structured data to a page
  2. Save and publish
  3. Test with Rich Results Test
  4. Fix any errors or warnings
  5. 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

Support

For questions or issues:

  1. Check this documentation first
  2. Validate your structured data with online tools
  3. Review Google Search Console for specific errors
  4. Consult Schema.org documentation for specific types