Un assistant qui va chercher votre page pour répondre à une question lit la réponse HTTP telle qu'elle arrive : le texte présent dans le HTML, pas celui qu'un script aurait construit ensuite. Cette page montre ce que voit un fetcher sans navigateur, comment le test GEO le mesure, et comment rendre le contenu côté serveur selon votre pile, Twig, WordPress, Shopify ou Next.js.
1. Sans navigateur
Ce que le fournisseur documente. Google est le seul éditeur à documenter son exécution du JavaScript : ses robots traitent les pages « en trois phases principales : exploration, rendu, indexation », le rendu est mis en file d'attente et la page « peut rester dans cette file quelques secondes, mais cela peut prendre plus longtemps ». Et la phrase qui compte pour les assistants : « le rendu côté serveur ou le pré-rendu reste une excellente idée, parce qu'il rend votre site plus rapide pour les utilisateurs et les robots, et tous les robots ne peuvent pas exécuter JavaScript » (Google, principes de base du SEO JavaScript). OpenAI, Anthropic et Perplexity ne documentent pas si leurs fetchers exécutent du JavaScript ; nous ne l'affirmons donc pas.
Ce que nous recommandons. Partir du cas défavorable : considérer qu'un fetcher d'assistant lit le HTML brut, comme curl, et que tout ce qui n'y est pas n'existe pas pour lui. Ce n'est pas une hypothèse pessimiste, c'est la seule qui ne dépend d'aucune documentation absente. Un site rendu côté serveur ne perd rien si les fetchers exécutent le JavaScript ; un site rendu côté client perd tout s'ils ne le font pas.
Les coquilles que nous rencontrons le plus souvent ne sont pas des applications monopages assumées. Ce sont des sites ordinaires dont un morceau a basculé côté client sans que personne ne le décide : un constructeur de pages qui charge les blocs de texte par appel AJAX après le premier affichage, un thème qui remplit le menu et le pied de page en script, un bandeau de consentement qui remplace le contenu par un écran d'attente tant que le visiteur n'a pas cliqué, une boutique dont la fiche produit arrive par une API après le chargement du gabarit vide. Dans le navigateur, tout est là ; dans la réponse HTTP, il ne reste qu'un titre et une balise div.
Comment le vérifier
Le test GEO lit votre page d'accueil sans exécuter de script et rapporte, dans la dimension « Extractibilité du contenu » : « Texte lisible sans JavaScript : n caractères (x % du HTML) », « Titre h1 unique : n trouvé(s) », « Titres h2 : n », « Balise <title> de 10 à 70 caractères », « Meta description de 50 à 170 caractères », « Balise canonical » et « Attribut lang sur <html> ». Moins de 300 caractères de texte, ou un texte inférieur à 5 % du HTML, est signalé comme une coquille probable. En ligne de commande, la même mesure tient en une ligne.
# le texte qu'un fetcher sans navigateur peut extraire de votre page
curl -s https://votre-site.fr/ | sed -e 's/<script[^>]*>.*<\/script>//g' -e 's/<[^>]*>//g' | tr -s ' \n' | wc -w
# comparez avec ce que vous lisez dans le navigateur : un rapport de 1 à 10 signale un rendu client
2. Rendu serveur par pile : Twig, WordPress, Shopify, Next.js
Ce que le fournisseur documente. Google recommande « un code de statut significatif, comme un 404 pour une page introuvable ou un 401 pour une page derrière une connexion », parce que « Googlebot utilise les codes de statut HTTP pour savoir si quelque chose s'est mal passé pendant l'exploration ». Une application cliente qui répond 200 sur toutes les routes et affiche l'erreur après exécution du script contredit cette règle (Google, principes de base du SEO JavaScript).
Ce que nous recommandons. Le correctif dépend de la pile, mais la règle est la même partout : le contenu est produit par le serveur, le script n'ajoute que l'interaction. Sur Symfony et Twig, c'est le comportement par défaut. Sur WordPress aussi, sauf constructeur de pages ou extension qui injecte le contenu par appel AJAX après chargement. Sur Shopify, les gabarits Liquid rendent côté serveur ; le risque vient des applications qui remplacent un bloc par un script. Sur Next.js, le rendu serveur existe mais doit être choisi : composants serveur ou getServerSideProps, pas un useEffect qui va chercher le contenu après coup.
Comment le vérifier
Pile par pile, le même geste : ouvrir le code source de la page, pas l'inspecteur, qui montre le DOM après exécution des scripts. Sur WordPress, désactivez JavaScript dans les outils de développement et rechargez : un contenu qui disparaît venait d'un script. Sur Shopify, cherchez dans le code source le texte de la fiche produit ; s'il n'y est pas, une application l'injecte. Sur Next.js, curl sur l'URL de la page suffit : un composant serveur renvoie le HTML rempli, un composant client renvoie la coquille et le script.
Comment le corriger
{# Twig : le contenu est dans la réponse #}
<main><h1>{{ page.title }}</h1>{{ page.body|raw }}</main>
// WordPress : contenu dans le gabarit, pas dans un appel AJAX après chargement
<?php the_title('<h1>', '</h1>'); the_content(); ?>
{% comment %} Shopify Liquid : le gabarit rend le produit côté serveur {% endcomment %}
<h1>{{ product.title }}</h1><div>{{ product.description }}</div>
// Next.js (App Router) : composant serveur, le HTML part rempli
export default async function Page() {
const post = await getPost();
return <main><h1>{post.title}</h1><article>{post.body}</article></main>;
}
3. Ce qui doit rester dans le HTML brut
Ce que le fournisseur documente. « Des éléments title uniques et descriptifs et des meta descriptions aident les utilisateurs à identifier rapidement le meilleur résultat », et Google précise qu'on peut « utiliser JavaScript pour définir ou modifier la meta description ainsi que l'élément title », dans le cadre de son propre rendu (Google, principes de base du SEO JavaScript). Aucun éditeur d'assistant ne documente une telle tolérance.
Ce que nous recommandons. Six choses dans la réponse initiale, sans exception : le title, la meta description, la canonique, le h1 et les intertitres, le texte des paragraphes, et les blocs JSON-LD, dont l'entité Organization détaillée dans Schema Organization et identité d'entité. Les liens de navigation aussi : un menu construit par script est un site sans structure pour un lecteur sans script. Tout le reste, formulaires, cartes, carrousels, animations, peut attendre le JavaScript.
Deux cas se discutent. La pagination et les filtres d'une liste : les premières pages doivent être de vraies URL avec leur contenu, le raffinement peut venir du script. Les blocs chargés au défilement, avis clients ou articles liés : acceptables s'ils sont secondaires, à condition que le texte qui répond à la question soit déjà là. La règle de décision est simple : si un lecteur qui n'a que le HTML brut peut répondre à la question que la page promet de traiter, la page est extractible ; sinon, ce qui manque est ce qu'il faut rendre côté serveur, et rien d'autre.
Comment le vérifier
# les six éléments, extraits du HTML brut
curl -s https://votre-site.fr/page | grep -oE '<title>[^<]*|<meta name="description"[^>]*|<link rel="canonical"[^>]*|<h1[^>]*>[^<]*|application/ld\+json'
Ce que nous avons fait sur seoforge.fr
Chaque page de ce site est rendue côté serveur par des gabarits Twig : titre, meta, canonique, texte, JSON-LD et navigation sont dans la réponse HTTP. Le seul contenu chargé après coup est le résultat de nos outils gratuits, servi par un fragment marqué noindex ; la page de l'outil est complète sans lui. Le test GEO, lancé sur notre page d'accueil, mesure ce texte sans exécuter de script.
Pour aller plus loin
Cette page détaille la deuxième dimension du guide du référencement IA. Pour prouver ce que chaque robot reçoit réellement, requête par requête, lisez vérifier l'accès de ChatGPT à votre site. Si le texte est là et que vous restez absent des réponses, l'Audit GEO reprend les six dimensions sur vos pages prioritaires.
Questions fréquentes
Les IA lisent-elles le JavaScript ? Seul Google documente l'exécution du JavaScript par ses robots, avec une file de rendu dont la durée n'est pas garantie. OpenAI, Anthropic et Perplexity ne documentent rien sur ce point. La seule hypothèse qui ne dépend d'aucune documentation absente est que le fetcher lit le HTML brut : c'est celle que nous retenons.