Données structurées React Router 7 : booster SEO et rich snippets
Apprends à configurer les données structurées dans React Router 7 et augmente l’impact SEO de tes pages grâce aux rich snippets et JSON-LD.
À quoi servent les données structurées ?
Tu as déjà optimisé tes balises title et description (voir la leçon
Configurer les balises meta SEO).
Prochaine étape : aider Google à comprendre ton contenu pour afficher un
résultat enrichi (rich snippet) : étoiles, image, durée d’une recette, prix…
Ces informations proviennent d’un bloc JSON-LD placé dans le <head>.
L’énorme avantage :
- zéro impact visuel : c’est invisible pour l’utilisateur ;
- grande valeur SEO : taux de clic (CTR) boosté jusqu’à +30 %.
Dans React Router 7 (ex-Remix) c’est ultra simple : une resource route ou
la fonction meta() suffit.
Installer la typisation Schema .org
Au lieu d’écrire du JSON brut (casse-pieds !), on va utiliser
schema-dts :
il expose tous les types Schema.org en TypeScript.
1npm install schema-dts
Note
Créer un composant ArticleStructuredData
1import type { Article } from "schema-dts";23export function ArticleStructuredData(props: Article) {4return (5<script6type="application/ld+json"7dangerouslySetInnerHTML={{ __html: JSON.stringify(props) }}8/>9);10}
Pourquoi un composant ? Tu restes en JSX, tu bénéficies de l’autocomplétion et tu peux l’appeler depuis n’importe quelle route.
Injecter le JSON-LD dans la page article
1import { ArticleStructuredData } from "~/components/ArticleStructuredData";2import { useLoaderData } from "react-router";3import { fetchArticle } from "~/server/articles.server";45/* ---------------- loader ---------------- */6export async function loader({ params }: Route.LoaderArgs) {7const article = await fetchArticle({ slug: params.slug });8if (!article)9throw new Response("Article introuvable", { status: 404 });10return article;11}1213/* ---------------- composant page ---------------- */14export default function ArticlePage() {15const article = useLoaderData<typeof loader>();1617return (18<>19<ArticleStructuredData20{"@context"="https://schema.org"}21{"@type"="Article"}22headline={article.title}23image={article.image}24datePublished={article.dateCreated.toISOString()}25author={{26"@type": "Person",27name: article.author,28}}29/* ^? autocomplétion assurée par schema-dts */30/>3132{/* …le reste de ton template Markdown / MDX… */}33</>34);35}
Points clés du transcript (reformulés) :
- Google ne « devine » rien : toutes les infos viennent de ton objet
article. - On garde un JSON minimaliste – inutile de remplir les 40 champs possibles, concentre-toi sur ceux demandés par la doc Article Google.
- Le composant se place avant le contenu : Google le lit sans scroller.
Alternative : générer via meta()
Tu préfères la fonction traditionnelle ?
1import { generateMeta } from "@forge42/seo-tools/remix/metadata";2import { article as articleLD } from "@forge42/seo-tools/structured-data/article";34export const meta = ({ data }: Route.MetaArgs) =>5generateMeta(6{7title: data.title,8description: data.description,9url: data.slug, // absolu conseillé10},11[12{13"script:ld+json": articleLD({14"@type": "Article",15headline: data.title,16image: data.image,17datePublished: data.dateCreated.toISOString(),18author: { "@type": "Person", name: data.author },19}),20},21],22);
Cette approche colle au transcript : la lib Forge42 écrit le <script> à
ta place. À toi de choisir la méthode qui te convient, l’important est que le
script atterrisse dans le <head>.
Valider ta structure : deux outils gratuits
- Rich Results Test – l’outil officiel Google, affichage desktop + mobile.
- Schema Markup Validator – l’ex-outil de test Schema.org, pratique hors connexion.
Copie/colle le HTML généré ou pointe directement ton URL : tu dois voir « Aucun avertissement critique ».
Tip
Gérer plusieurs types : Article et Organisation
Les SERP aiment connaître ton entité (marque, blog, association) :
1import { Organization } from "schema-dts";23export function RootStructuredData() {4const org: Organization = {5"@context": "https://schema.org",6"@type": "Organization",7name: "Algomax",8url: "https://algomax.fr",9logo: "https://algomax.fr/logo.svg",10};11return (12<script13type="application/ld+json"14dangerouslySetInnerHTML={{ __html: JSON.stringify(org) }}15/>16);17}
Place-le dans app/root.tsx juste avant <Meta />.
Ainsi, TOUTES les pages héritent de l’Organisation ; chaque article ajoute
ensuite son propre script.
Pièges fréquents
| Problème | Solution |
|---|---|
| Script rendu dans le body | Place-le via meta() ou dans un composant monté avant le premier <h1>. |
URL relatives (/cover.jpg) | Convertis en URL absolues (https://…/cover.jpg). |
| Titre dupliqué | Supprime l’ancien <MetaTags> seulement dans la page où tu injectes generateMeta. |
Types inconnus (ex. TechArticle) | Vérifie dans schema.org ; Google ne supporte pas tout. |
Warning
Checklist avant de déployer
- Un seul
<script type="application/ld+json">par type de page. - Toutes les URL (
url,image,logo) sont absolues. - Validation Google : 0 erreur et 0 warning critique.
- Pages sensibles (
/login,/register) : pas de JSON-LD inutile. - CI verte : la build ne casse pas (typage
schema-dts).
Important
Pousse ! Dans 48 h la Search Console devrait t’indiquer
“Améliorations → Article – Valides ✔︎”.
Un petit pas pour toi, un bond pour le CTR de ton blog 😎
Comprendre les concepts fondamentaux
Quelle est la principale différence entre les composants client et serveur dans React ?
Optimisation des performances
Quelle technique est recommandée pour éviter les rendus inutiles dans React ?
Architecture des données
Quel hook permet de gérer les effets de bord dans un composant React ?