SEO Structured Data Implementation - Summary (Updated)
✅ Implementation Complete
Structured data (Schema.org JSON-LD) support has been successfully added to all three Baldr projects with the correct React Router compatible approach.
🔧 Fix Applied
Issue: React Router's meta() function only supports 'link' and 'meta' tags, not 'script' tags.
Solution: Created a custom hook and component approach to inject structured data into the document head dynamically.
📁 Changes Made
1. baldr-template (Frontend)
File: app/utils/meta.util.ts
- ✅ Added
structuredDatafield toPageSEOinterface - ✅ Added
structuredDataTemplatesobject with helper functions for common schema types:- Organization
- WebPage
- Article
- Product
- BreadcrumbList
File: app/hooks/useStructuredData.ts ⭐ NEW
- ✅ Created custom hook to inject structured data into document head
- ✅ Automatically manages script tag lifecycle
- ✅ Removes old structured data when component unmounts
File: app/components/StructuredData.tsx ⭐ NEW
- ✅ Created reusable component for rendering structured data
- ✅ Can be used in any component for custom structured data
- ✅ Uses
dangerouslySetInnerHTMLto render JSON-LD
File: app/routes/_index.tsx
- ✅ Updated to import and use
useStructuredDatahook - ✅ Automatically injects structured data from page SEO metadata
File: app/routes/$.tsx
- ✅ Updated to import and use
useStructuredDatahook - ✅ Automatically injects structured data for all dynamic pages
Result: Pages automatically render structured data in the <head> section via the React hook.
2. Baldr-Bo (Back Office)
File: app/utils/seo/meta.ts
- ✅ Updated
buildMeta()to support structured data rendering - ✅ Added
structuredDataTemplateshelper functions
File: app/components/organisms/modules/seo/pageFormSeo.organism.tsx
- ✅ Added structured data textarea field in SEO form
- ✅ Added JSON validation on input
- ✅ Added helpful documentation and examples in the form
- ✅ Added schema type reference guide
Result: Administrators can now add and edit structured data directly in the page editor's SEO tab.
3. BaldrTs (Backend)
Verification:
- ✅ Already had full support for structured data
- ✅ Field exists in
src/models/schemas/seo.schema.ts - ✅ Interface defined in
src/interfaces/page.interface.ts - ✅ Stored as
Schema.Types.Mixedin MongoDB
Result: Backend was already ready - no changes needed!
📚 Documentation Updated
All documentation files have been updated to reflect the correct implementation:
- STRUCTURED_DATA_GUIDE.md - Updated with hook usage
- STRUCTURED_DATA_QUICKREF.md - Updated with hook example
- STRUCTURED_DATA_EXAMPLE.md - Updated with complete walkthrough
Location:
- BaldrTs:
documents/ - Baldr-Bo:
docs/ - baldr-template:
documents/
🚀 How to Use
For Administrators (Baldr-Bo)
- Open a page in the page editor
- Navigate to the SEO tab
- Scroll to "Données structurées (Schema.org JSON-LD)"
- Paste your JSON-LD structured data
- Save the page
For Developers (baldr-template)
Automatic Method (Recommended)
Pages using the standard route pattern automatically inject structured data:
// routes/_index.tsx or routes/$.tsx
import { useStructuredData } from "~/hooks/useStructuredData";
export default function MyPage({ loaderData }: Route.ComponentProps) {
// This hook automatically injects structured data into <head>
useStructuredData(loaderData?.page?.seo?.structuredData);
return <div>Your page content</div>;
}
Manual Method
For custom structured data or pages without loader data:
import { useStructuredData } from "~/hooks/useStructuredData";
import { structuredDataTemplates } from "~/utils/meta.util";
export default function CustomPage() {
const structuredData = structuredDataTemplates.organization({
name: "Your Company",
url: "https://yourwebsite.com",
logo: "https://yourwebsite.com/logo.png"
});
useStructuredData(structuredData);
return <div>Your page content</div>;
}
Component Method
Alternatively, use the component directly in JSX:
import StructuredData from "~/components/StructuredData";
export default function MyPage() {
const schema = {
"@context": "https://schema.org",
"@type": "WebPage",
"name": "My Page"
};
return (
<>
<StructuredData data={schema} />
<div>Your page content</div>
</>
);
}
For Backend (BaldrTs)
No changes needed - structured data is already supported in the API:
// Example API request
POST /api/pages
{
"title": "My Page",
"seo": {
"metaTitle": "My Page Title",
"structuredData": {
"@context": "https://schema.org",
"@type": "WebPage",
"name": "My Page"
}
}
}
🎯 Benefits
- Enhanced Search Results: Rich snippets with ratings, prices, images
- Better SEO: Search engines understand your content better
- Voice Search: Improved compatibility with voice assistants
- Knowledge Graph: Potential inclusion in Google's Knowledge Graph
- Featured Snippets: Higher chance of appearing in position zero
🔧 Validation Tools
- Google Rich Results Test: https://search.google.com/test/rich-results
- Schema Markup Validator: https://validator.schema.org/
- JSON Validator: https://jsonlint.com/
📋 Common Schema Types Supported
| Type | Use Case |
|---|---|
| Organization | Homepage, About pages |
| WebPage | Standard content pages |
| Article | Blog posts, News articles |
| Product | E-commerce products |
| BreadcrumbList | Navigation breadcrumbs |
| FAQPage | FAQ sections |
| LocalBusiness | Physical store locations |
| Event | Events, conferences |
| VideoObject | Video content pages |
⚠️ Important Notes
- Validation is Critical: Always validate with Google Rich Results Test before publishing
- Match Page Content: Structured data must match visible page content
- Keep Updated: Maintain accurate data (prices, availability, dates)
- No Spam: Don't add fake reviews or misleading information
- Be Patient: Rich results can take weeks to appear in search
🎓 Learning 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/
🐛 Troubleshooting
Error: "A meta object uses an invalid tagName: script"
This error occurs when trying to render script tags through React Router's meta() function.
Solution: Use the useStructuredData hook instead, which properly injects the script tag into the document head.
Structured data not appearing in page source
Check:
- Verify the hook is being called:
useStructuredData(loaderData?.page?.seo?.structuredData) - Check browser DevTools → Elements →
<head>section - Look for
<script type="application/ld+json">
JSON validation errors
Use an online JSON validator (jsonlint.com) to check your JSON syntax before saving.
📞 Support
For questions or issues:
- Check the documentation in
STRUCTURED_DATA_GUIDE.md - Use the quick reference in
STRUCTURED_DATA_QUICKREF.md - Follow the examples in
STRUCTURED_DATA_EXAMPLE.md - Validate with online tools
- Review Google Search Console for specific errors
✨ What's Next
Suggested enhancements (optional):
- Add structured data templates directly in the Back Office UI
- Create a visual structured data builder
- Add automatic validation in the form
- Generate structured data automatically from page content
- Monitor structured data performance in analytics
Implementation Date: January 8, 2026 Status: ✅ Complete and Ready to Use Last Updated: January 8, 2026 - Fixed React Router compatibility