Tenten AIGEO
Retour au blog
AEO techniqueMise en œuvre

Injecter du JSON-LD dans l’App Router de Next.js avec un Server Component

Dans l’App Router de Next.js, un Server Component peut générer directement une balise `<script type="application/ld+json">`. Les données structurées figurent ainsi dans le HTML initial et peuvent être lues par les robots d’exploration des IA sans exécuter JavaScript. Avec un exemple minimal dans page.tsx, le regroupement de plusieurs entités via @graph et les vérifications à effectuer avec curl avant la mise en ligne.

L’équipe Tenten GEOPublié le 2026-06-115 min de lecture
Schéma montrant les données structurées générées par le serveur arriver directement dans le HTML initial lu par le robot d’exploration de l’IA.

La méthode la plus fiable pour injecter du JSON-LD avec l’App Router consiste à générer directement une balise `<script type="application/ld+json">` dans un Server Component. Les données structurées figurent alors dans le HTML initial renvoyé par le serveur, ce qui permet aux robots d’exploration des IA de les lire sans exécuter JavaScript. À l’inverse, le JSON-LD ajouté après coup avec useEffect ou Google Tag Manager est pratiquement invisible pour les moteurs de réponse : la plupart terminent leur exploration et quittent la page sans attendre son hydratation.

Pourquoi faut-il générer le JSON-LD côté serveur ?

Tout est une question de timing. Dès la requête, le Server Component inscrit le JSON-LD dans la chaîne HTML. Le premier fichier récupéré par des robots comme GPTBot, ClaudeBot, PerplexityBot ou Google-Extended contient donc le schéma complet. Une injection côté client suppose en revanche que le navigateur télécharge puis exécute votre bundle, une étape que la plupart des robots d’exploration des IA n’effectuent pas. Un piège peut fausser le diagnostic : le test des résultats enrichis de Google exécute JavaScript. Les données injectées côté client y semblent donc parfaitement normales et vous pouvez croire la validation acquise. Pourtant, lorsqu’un moteur de réponse consulte réellement la page, il récupère souvent le HTML source non rendu, dépourvu de tout schéma. Dans les audits techniques que nous réalisons pour nos clients, c’est l’un des défauts les plus fréquents et les plus faciles à manquer.

Exemple minimal viable : une seule page page.tsx

L’implémentation tient en peu de code. Aucun package supplémentaire ni aucune route API ne sont nécessaires : tout se passe dans le Server Component qui affiche l’article. Trois opérations suffisent : récupérer les données, regrouper les objets et générer la balise script.

  1. Dans `app/blog/[slug]/page.tsx`, qui est un Server Component par défaut, utilisez d’abord `await` pour récupérer les données de l’article.
  2. Construisez un objet JavaScript simple nommé `jsonLd`. Commencez par `"@context": "https://schema.org"` et `"@type": "Article"`, puis renseignez dynamiquement les autres propriétés — headline, datePublished, author et image — à partir des données de l’article.
  3. Placez au début du JSX renvoyé : `<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, "\\u003c") }} />`.
  4. N’importez aucune bibliothèque côté client et n’ajoutez pas `"use client"` en tête du fichier. Dans ce dernier cas, le composant devient un Client Component et tout le bénéfice de cette mise en œuvre disparaît.

Relier plusieurs entités avec @graph

Une page a généralement besoin de plusieurs schémas : Organization pour la marque, Article pour le contenu, BreadcrumbList pour le fil d’Ariane et FAQPage pour la foire aux questions. Plutôt que de générer quatre balises script indépendantes, il est plus propre de réunir ces entités dans le tableau `@graph` d’un même objet JSON-LD, puis de les relier au moyen de `@id`. Vous pouvez, par exemple, faire pointer la propriété `publisher` d’Article vers le `@id` d’Organization, et le dernier élément de BreadcrumbList vers le `@id` de la page courante. Le moteur de réponse obtient ainsi, en une seule analyse, une représentation complète des relations entre les entités, avec moins de risques de rencontrer des nœuds contradictoires ou dupliqués.

  • Organization et WebSite : placez-les dans `app/layout.tsx` afin de les partager une seule fois sur l’ensemble du site. Ne les redéclarez pas sur chaque page.
  • Article ou BlogPosting : placez-le dans le fichier `page.tsx` de l’article et renseignez dynamiquement ses propriétés avec les données de la page courante.
  • BreadcrumbList : construisez-le selon la hiérarchie des routes. Il aide tout particulièrement les IA à comprendre l’architecture du site.
  • FAQPage : ne l’ajoutez que si la page comporte réellement une section de questions-réponses. Le texte de `acceptedAnswer` doit correspondre au contenu visible. Ne créez pas une fausse FAQ uniquement pour disposer de ce schéma.
Infographie : le Server Component génère le JSON-LD dans le HTML initial, tandis que le robot d’exploration de l’IA ignore l’injection côté client.
Le JSON-LD généré par le serveur figure dans le HTML initial ; celui injecté côté client risque d’arriver trop tard pour le robot d’exploration.

Rendre le JSON-LD facile à maintenir

Si les objets de schéma sont dispersés dans toutes les pages, plus personne n’osera les modifier trois mois plus tard. Notre approche consiste à les centraliser dans `lib/schema.ts` et à utiliser les types de `schema-dts` (`import type { Article, WithContext } from "schema-dts"`) pour contraindre la valeur renvoyée par chaque fonction de génération. En cas de nom de propriété ou de type incorrect, TypeScript signale l’erreur dès la compilation. La page se contente d’appeler `buildArticleSchema(post)`, de récupérer un objet typé de manière sûre, puis de le générer. Toute modification s’applique ainsi à l’ensemble du site. Les URL sont toujours absolues et centralisées dans une constante `SITE_URL`, afin d’éviter que les `@id` ne divergent entre le site officiel et le domaine de prévisualisation.

Erreurs fréquentes et vérifications avant la mise en ligne

  • Les valeurs `url`, `image` ou `datePublished` du JSON-LD ne correspondent pas au contenu réellement affiché. Le moteur de réponse repère cette incohérence, ce qui réduit la fiabilité perçue de toute la page.
  • L’utilisation de chemins relatifs dans `@id` ou `url` peut les faire pointer vers le mauvais emplacement dès que vous passez sur le domaine de prévisualisation.
  • Vous avez oublié d’échapper `<` ou ajouté par inadvertance `"use client"` en tête de la page, ce qui repousse la génération de la balise script côté client.
  • Avant la mise en ligne, vérifiez la syntaxe avec le test des résultats enrichis de Google, puis récupérez directement le HTML source de la page avec `curl`. Vous pourrez ainsi confirmer que la balise script figure bien dans la réponse initiale et pas uniquement dans les DevTools du navigateur. Cette vérification est décisive, car elle reproduit exactement ce que voit le robot d’exploration de l’IA.
Sur les sites que nous avons audités, le principal problème ne vient généralement pas d’un schéma mal rédigé, mais d’un JSON-LD uniquement présent côté client. S’il n’apparaît pas dans le HTML renvoyé par le serveur, l’IA le considère comme inexistant.Tenten GEO Technical Audit

De l’implémentation à la citation comme source

Déplacer le JSON-LD dans un Server Component constitue le minimum requis pour rendre un contenu « lisible par les machines ». Il faut ensuite harmoniser la dénomination des entités, le maillage interne et les informations publiées d’une page à l’autre, afin que les IA puissent vous citer durablement comme une source fiable. Si vous ignorez si les données structurées de votre site figurent bien dans le HTML consulté par les robots, vous pouvez prendre rendez-vous pour un diagnostic GEO de 30 minutes. Nous analyserons le code source réellement récupéré afin d’identifier les lacunes, au lieu de nous limiter à la page rendue à l’écran.

Questions fréquentes

Comment ajouter du JSON-LD à l’App Router de Next.js ?
Construisez un objet de schéma dans le Server Component (`page.tsx` ou `layout.tsx`), puis générez-le avec `<script type="application/ld+json">` et `dangerouslySetInnerHTML`, en échappant le caractère `<` de la chaîne par `<`. Les données structurées figureront ainsi dans le HTML initial et pourront être lues par les robots d’exploration des IA sans exécution de JavaScript.
Peut-on ajouter du JSON-LD avec next/head ou l’API Metadata ?
L’App Router n’utilise plus next/head, et l’API Metadata ne permet pas de générer librement des balises script. Next.js recommande officiellement d’afficher directement `<script type="application/ld+json">` dans le JSX du Server Component. C’est actuellement la méthode la plus stable pour intégrer du JSON-LD et la plus simple à lire pour les robots d’exploration.
Pourquoi est-il déconseillé d’injecter les données structurées avec GTM ou useEffect ?
Ces deux méthodes s’exécutent côté client : le JSON-LD n’apparaît qu’après l’hydratation de la page par le navigateur. Or, la plupart des robots d’exploration des IA se contentent du HTML initial et n’exécutent pas JavaScript ; votre schéma leur reste donc invisible. Seule une génération côté serveur garantit que les données structurées puissent réellement être lues et exploitées comme référence par le moteur de réponse.

PASSEZ À L’ÉTAPE SUIVANTE

Votre marque apparaît-elle dans les réponses des IA ?

En 30 minutes, nous identifions vos écarts de visibilité sur les principaux moteurs IA et les actions à traiter en priorité.

Réserver le diagnostic