[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fRXpHpo8gNDFAr7PNeLJ9CFJdN1__LFtZpxNVpVUplJQ":3,"$f50x2Py5iFEJkHmyo8867w9OuBUin1hPwH1zjDWtuZPw":27},{"_id":4,"slug":5,"__v":6,"author":7,"body":8,"canonical":9,"category":10,"createdAt":11,"date":12,"description":13,"htmlContent":14,"image":15,"imageAlt":15,"readingTime":16,"tags":17,"title":25,"updatedAt":26},"6a01ef92aa6b273b0c7c5bdc","google-s-mueller-on-why-ai-built-websites-miss-seo-basics-via-sejournal-mattgsouthern",0,"Equipe Seogard","John Mueller, Search Advocate chez Google, a posé le diagnostic sans détour : les outils d'IA générative produisent des sites fonctionnels en quelques minutes, mais ignorent systématiquement les fondamentaux techniques du SEO. Pas de `robots.txt`, pas de `sitemap.xml`, pas de balises canonical, pas de gestion propre des status codes. Le \"vibe coding\" — cette pratique qui consiste à décrire un site en langage naturel et laisser l'IA le construire — livre du code qui compile, mais qui reste invisible pour les moteurs de recherche.\n\nCe constat n'est pas une opinion. C'est une observation vérifiable sur la quasi-totalité des projets générés par Bolt, v0, Lovable ou Claude Artifacts. Et les conséquences sur des sites de plusieurs milliers de pages sont dévastatrices.\n\n## Le problème structurel : l'IA optimise pour le navigateur, pas pour le crawler\n\nLes LLM qui génèrent du code web sont entraînés sur des corpus massifs de code source. Leur objectif d'optimisation : produire du code qui fonctionne visuellement dans un navigateur. Le rendu Googlebot n'a jamais fait partie de leur fonction de loss.\n\nConcrètement, quand vous demandez à un outil comme Bolt de créer un site e-commerce, vous obtenez un SPA React avec du client-side rendering, des routes dynamiques gérées par React Router, et zéro indication pour les robots d'indexation. Le site s'affiche parfaitement dans Chrome. Googlebot, lui, voit une coquille vide.\n\n### L'absence de SSR comme symptôme\n\nLa majorité des sites AI-built utilisent des frameworks SPA (React, Vue) sans configuration SSR. Le code généré ressemble à ceci :\n\n```html\n\u003C!DOCTYPE html>\n\u003Chtml lang=\"en\">\n\u003Chead>\n  \u003Cmeta charset=\"UTF-8\" />\n  \u003Cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n  \u003Ctitle>MonShop\u003C/title>\n\u003C/head>\n\u003Cbody>\n  \u003Cdiv id=\"root\">\u003C/div>\n  \u003Cscript type=\"module\" src=\"/src/main.tsx\">\u003C/script>\n\u003C/body>\n```\n\nC'est le HTML complet que Googlebot reçoit lors du premier fetch. Pas de balise `\u003Cmeta name=\"description\">`, pas de `\u003Clink rel=\"canonical\">`, pas de données structurées, pas de contenu textuel. Tout dépend de l'exécution JavaScript côté client.\n\nGoogle peut exécuter du JavaScript, mais avec un délai. La [documentation officielle de Google sur le JavaScript SEO](https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics) rappelle que le rendering se fait dans une \"file d'attente de rendu\" séparée du crawl initial. Sur un site de 8 000 pages produit en vibe coding, cela signifie potentiellement des semaines avant que le contenu soit réellement indexé — si le crawl budget le permet.\n\nLe problème ne se limite pas au SSR. Même sur des sites statiques générés par IA, les éléments SEO critiques sont absents par défaut, simplement parce que personne ne les a demandés dans le prompt.\n\n### Ce que Mueller dit vraiment\n\nLa position de Mueller, [relayée par Search Engine Journal](https://www.searchenginejournal.com/googles-mueller-vibe-coding-wont-handle-your-seo-for-you/574237/), se résume en une phrase : les outils d'IA ne font que ce que vous leur demandez explicitement. Si votre prompt dit \"crée un site vitrine pour un cabinet d'architecte\", vous obtenez des composants visuels. Vous n'obtenez pas un `robots.txt` configuré, un `sitemap.xml` dynamique, une gestion des canonicals sur les pages paginées, ni des redirections 301 sur les anciennes URLs.\n\nCe n'est pas un bug. C'est le fonctionnement normal d'un LLM : il résout le problème posé. Le SEO technique n'est jamais \"le problème posé\" par un non-spécialiste.\n\n## Les cinq failles SEO récurrentes des sites AI-built\n\nAprès audit de plusieurs dizaines de sites générés par des outils de vibe coding (Bolt, v0, Lovable, Replit Agent), un pattern émerge. Les mêmes failles reviennent systématiquement.\n\n### 1. Absence de robots.txt\n\nAucun des outils testés ne génère de fichier `robots.txt` par défaut. Sur un site Next.js ou Astro classique, ce fichier est souvent configuré manuellement ou via un plugin. Sur un site AI-built, il n'existe tout simplement pas.\n\nL'absence de `robots.txt` n'empêche pas l'indexation — Googlebot crawle par défaut tout ce qu'il trouve. Mais elle empêche le contrôle du crawl budget. Sur un site e-commerce avec des pages de filtres (couleur, taille, prix), l'absence de `robots.txt` laisse Googlebot crawler des milliers de combinaisons de paramètres URL sans valeur d'indexation.\n\nVoici un `robots.txt` minimal qu'aucun outil IA ne génère, mais que tout site de plus de 500 pages devrait avoir :\n\n```txt\nUser-agent: *\nDisallow: /api/\nDisallow: /checkout/\nDisallow: /account/\nDisallow: /search?*\nDisallow: /*?sort=\nDisallow: /*?filter=\n\nUser-agent: GPTBot\nDisallow: /\n\nUser-agent: Google-Extended\nDisallow: /\n\nSitemap: https://www.monshop.fr/sitemap.xml\n```\n\nNotez les deux derniers blocs : la gestion des bots IA (GPTBot, Google-Extended) est un sujet en soi que les outils de vibe coding ignorent totalement. Si vous gérez un site dont le contenu propriétaire a de la valeur, [ces directives de contrôle des bots IA](/blog/your-managed-wordpress-might-be-blocking-ai-bots-and-you-can-t-see-it) deviennent critiques, et Google teste d'ailleurs [un nouveau standard d'autorisation des bots](/blog/google-is-testing-new-bot-authorization-standard-via-sejournal-martinibuster).\n\n### 2. Pas de sitemap.xml\n\nMême constat. Les outils IA ne génèrent pas de sitemap. Sur un blog de 30 pages, l'impact est faible — Googlebot trouvera les pages via les liens internes. Sur un catalogue de 12 000 produits avec une arborescence à 4 niveaux de profondeur, l'absence de sitemap signifie que les pages orphelines ou faiblement maillées ne seront jamais découvertes.\n\n### 3. Canonicals absents ou incohérents\n\nC'est probablement la faille la plus dangereuse. Les sites AI-built ne posent jamais de balise `\u003Clink rel=\"canonical\">`. Sur un site avec des variantes d'URL (paramètres UTM, filtres, versions HTTP/HTTPS, trailing slashes), Google doit deviner la version canonique. Et Google devine mal, régulièrement.\n\n### 4. Meta tags génériques ou manquants\n\nQuand ils existent, les `\u003Ctitle>` et `\u003Cmeta description>` sont soit identiques sur toutes les pages, soit générés à partir du nom du composant React. Un audit Screaming Frog typique sur un site AI-built révèle 80 à 95 % de pages avec des titles dupliqués.\n\n### 5. Aucune gestion des erreurs HTTP\n\nPas de page 404 personnalisée, pas de redirections, pas de gestion des soft 404. Les routes inexistantes retournent souvent un status 200 avec le contenu de la page d'accueil — le pire scénario possible pour l'indexation.\n\n## Scénario concret : migration d'un catalogue e-commerce vers un site AI-built\n\nPrenons un cas réaliste. Une marque de mobilier DTC (direct-to-consumer) exploite un site Shopify de 4 200 pages (850 produits, 120 collections, le reste en pages CMS et blog). Le trafic organique : 45 000 visites/mois, principalement sur des requêtes mid-tail (\"table basse chêne massif\", \"étagère murale métal noir\").\n\nL'équipe décide de reconstruire le site avec Bolt + Next.js pour gagner en flexibilité. Le prompt initial : \"Crée un site e-commerce de mobilier moderne avec un catalogue produit, des pages collection, un panier et un checkout.\" Bolt livre un site fonctionnel en 3 heures. Design propre, navigation fluide, composants réutilisables.\n\n### Ce que l'audit révèle\n\nDeux semaines après la mise en production, l'équipe SEO lance un crawl Screaming Frog :\n\n- **4 200 URLs crawlées**, dont 3 800 retournent un status 200 mais avec un `\u003Ctitle>` identique : \"MonMobilier | Accueil\"\n- **0 balise canonical** sur l'ensemble du site\n- **Aucun `robots.txt`** — Screaming Frog découvre 11 400 URLs crawlables en comptant les variantes de filtres\n- **Pas de sitemap.xml** — Google Search Console affiche \"Sitemap non détecté\"\n- **Toutes les pages produit** sont rendues en CSR : le HTML source ne contient que le `\u003Cdiv id=\"root\">`\n- Les anciennes URLs Shopify (`/products/table-basse-chene`) retournent un 404 au lieu de rediriger vers les nouvelles (`/catalogue/tables/table-basse-chene-massif`)\n\n### L'impact en chiffres\n\nEn 6 semaines :\n- Le trafic organique passe de 45 000 à 8 200 visites/mois\n- 2 100 pages précédemment indexées sont supprimées de l'index (vérifiable dans le rapport \"Pages\" de Search Console)\n- Les 850 pages produit ne sont toujours pas indexées — elles restent dans la file de rendering JavaScript de Google\n- Le rapport \"Couverture\" affiche 3 400 URLs en \"Découverte, actuellement non indexée\"\n\nCe scénario n'est pas hypothétique. C'est le pattern exact observé sur des dizaines de migrations vers des sites AI-built depuis début 2025.\n\n## Le kit technique de rattrapage : ce que l'IA ne fera pas pour vous\n\nCorriger un site AI-built pour le SEO revient à ajouter rétroactivement toute la couche technique que l'IA a ignorée. Voici les interventions prioritaires, avec du code prêt à l'emploi.\n\n### Forcer le SSR et injecter les meta tags côté serveur\n\nSi le site utilise Next.js (le framework le plus fréquemment généré par les outils IA), la correction passe par la migration des composants vers le App Router avec des metadata statiques ou dynamiques.\n\n```typescript\n// app/catalogue/[slug]/page.tsx\nimport { Metadata } from 'next'\nimport { getProduct } from '@/lib/api'\nimport { notFound } from 'next/navigation'\n\ninterface Props {\n  params: { slug: string }\n}\n\nexport async function generateMetadata({ params }: Props): Promise\u003CMetadata> {\n  const product = await getProduct(params.slug)\n\n  if (!product) {\n    notFound()\n  }\n\n  return {\n    title: `${product.name} — Mobilier design | MonMobilier`,\n    description: product.metaDescription || `${product.name} en ${product.material}. Livraison gratuite dès 500€. Fabrication française.`,\n    alternates: {\n      canonical: `https://www.monmobilier.fr/catalogue/${params.slug}`,\n    },\n    openGraph: {\n      title: product.name,\n      description: product.shortDescription,\n      images: [{ url: product.imageUrl, width: 1200, height: 630 }],\n    },\n  }\n}\n\nexport default async function ProductPage({ params }: Props) {\n  const product = await getProduct(params.slug)\n  if (!product) notFound()\n\n  return (\n    \u003Cmain>\n      \u003Ch1>{product.name}\u003C/h1>\n      {/* Contenu produit rendu côté serveur */}\n    \u003C/main>\n  )\n}\n```\n\nCe code fait trois choses essentielles que l'IA n'a pas faites : il rend la page côté serveur (Googlebot reçoit du HTML complet), il injecte un canonical explicite par page, et il retourne un vrai 404 quand le produit n'existe pas au lieu d'un soft 404.\n\nPour aller plus loin sur les pièges JavaScript spécifiques au SEO e-commerce, [les 5 leçons JavaScript SEO tirées de sites e-commerce majeurs](/blog/5-javascript-seo-lessons-from-top-ecommerce-sites) détaillent les patterns à éviter.\n\n### Générer le sitemap.xml dynamiquement\n\nNext.js App Router permet de générer un sitemap via une route `app/sitemap.ts`. Voici une implémentation qui couvre un catalogue produit et des pages CMS :\n\n```typescript\n// app/sitemap.ts\nimport { MetadataRoute } from 'next'\nimport { getAllProducts, getAllCollections, getAllBlogPosts } from '@/lib/api'\n\nexport default async function sitemap(): Promise\u003CMetadataRoute.Sitemap> {\n  const baseUrl = 'https://www.monmobilier.fr'\n\n  const products = await getAllProducts()\n  const collections = await getAllCollections()\n  const posts = await getAllBlogPosts()\n\n  const productUrls = products.map((p) => ({\n    url: `${baseUrl}/catalogue/${p.slug}`,\n    lastModified: new Date(p.updatedAt),\n    changeFrequency: 'weekly' as const,\n    priority: 0.8,\n  }))\n\n  const collectionUrls = collections.map((c) => ({\n    url: `${baseUrl}/collections/${c.slug}`,\n    lastModified: new Date(c.updatedAt),\n    changeFrequency: 'weekly' as const,\n    priority: 0.7,\n  }))\n\n  const blogUrls = posts.map((post) => ({\n    url: `${baseUrl}/blog/${post.slug}`,\n    lastModified: new Date(post.publishedAt),\n    changeFrequency: 'monthly' as const,\n    priority: 0.5,\n  }))\n\n  return [\n    { url: baseUrl, lastModified: new Date(), changeFrequency: 'daily', priority: 1.0 },\n    ...productUrls,\n    ...collectionUrls,\n    ...blogUrls,\n  ]\n}\n```\n\nSur un site de 4 200 pages, ce sitemap permet à Googlebot de découvrir l'intégralité du catalogue sans dépendre du maillage interne — maillage qui, sur un site AI-built, est souvent incomplet.\n\n### Configurer les redirections 301 pour la migration\n\nLe point que les outils IA ne gèrent jamais : le mapping des anciennes URLs. Lors d'une migration depuis Shopify, chaque ancienne URL doit pointer vers sa nouvelle destination. En Next.js, cela se configure dans `next.config.js` :\n\n```javascript\n// next.config.js\n/** @type {import('next').NextConfig} */\nconst nextConfig = {\n  async redirects() {\n    return [\n      // Mapping produits Shopify → nouvelle structure\n      {\n        source: '/products/:slug',\n        destination: '/catalogue/:slug',\n        permanent: true, // 301\n      },\n      // Mapping collections Shopify → nouvelle structure\n      {\n        source: '/collections/:slug',\n        destination: '/collections/:slug',\n        permanent: true,\n      },\n      // Pages spécifiques\n      {\n        source: '/pages/about',\n        destination: '/a-propos',\n        permanent: true,\n      },\n      // Catch-all pour les anciennes URLs de blog\n      {\n        source: '/blogs/journal/:slug',\n        destination: '/blog/:slug',\n        permanent: true,\n      },\n    ]\n  },\n  async headers() {\n    return [\n      {\n        source: '/:path*',\n        headers: [\n          {\n            key: 'X-Robots-Tag',\n            value: 'index, follow',\n          },\n        ],\n      },\n      {\n        // Bloquer l'indexation des pages de recherche interne\n        source: '/search',\n        headers: [\n          {\n            key: 'X-Robots-Tag',\n            value: 'noindex, nofollow',\n          },\n        ],\n      },\n    ],\n  },\n}\n\nmodule.exports = nextConfig\n```\n\nSur un site avec 850 produits, le mapping un-à-un est rarement suffisant. Les slugs changent entre Shopify et la nouvelle structure. La bonne pratique : exporter toutes les URLs Shopify via l'API, mapper chacune manuellement ou via un script, et tester les redirections avec un crawl Screaming Frog en mode \"list\" avant la mise en production.\n\n## Au-delà du code : la checklist d'audit pour tout site AI-built\n\nLe code ne suffit pas. Avant de mettre en production un site généré par IA, un audit systématique s'impose. Voici la procédure en cinq étapes, avec les outils associés.\n\n### Étape 1 : Valider le rendu Googlebot\n\nUtilisez l'outil d'inspection d'URL de Google Search Console. Soumettez 5-10 URLs représentatives (page d'accueil, page catégorie, page produit, article de blog, page de résultat de recherche interne). Comparez le HTML rendu avec le code source. Si le contenu principal n'apparaît pas dans le HTML source, vous avez un problème de CSR.\n\nAlternative pour un test rapide : Chrome DevTools > désactivez JavaScript (Settings > Debugger > Disable JavaScript) et rechargez la page. Ce que vous voyez est approximativement ce que Googlebot voit lors du premier fetch.\n\n### Étape 2 : Crawl complet avec Screaming Frog\n\nConfigurez Screaming Frog en mode \"JavaScript rendering\" (Configuration > Spider > Rendering > JavaScript). Lancez un crawl complet. Les métriques critiques à vérifier :\n\n- **Titles dupliqués** : triez par \"Title 1 Duplicate\" dans l'onglet Page Titles\n- **Meta descriptions manquantes** : filtre \"Missing\" dans l'onglet Meta Description\n- **Canonicals** : onglet Canonicals > vérifiez que chaque page a un canonical self-referencing\n- **Status codes** : triez par code de réponse, cherchez les soft 404 (pages retournant un 200 avec un contenu générique)\n- **Pages orphelines** : croisez les URLs du sitemap avec les URLs découvertes par le crawl\n\n### Étape 3 : Vérifier les fichiers techniques\n\nTestez manuellement :\n- `https://votre-site.fr/robots.txt` — doit exister et contenir des directives pertinentes\n- `https://votre-site.fr/sitemap.xml` — doit exister, être valide XML, et lister toutes les URLs indexables\n- Soumettez le sitemap dans Google Search Console si ce n'est pas déjà fait\n\n### Étape 4 : Tester les redirections\n\nSi vous migrez depuis un ancien site, exportez toutes les URLs indexées (Search Console > Pages > filtrer par \"Indexées\"). Testez chaque URL avec `curl` ou un crawl Screaming Frog en mode list :\n\n```bash\n# Tester le status code et la destination de redirection\ncurl -sI \"https://www.monmobilier.fr/products/table-basse-chene\" | grep -E \"HTTP/|Location:\"\n\n# Résultat attendu :\n# HTTP/2 301\n# location: https://www.monmobilier.fr/catalogue/table-basse-chene\n```\n\n### Étape 5 : Monitoring continu\n\nC'est le point que Mueller ne mentionne pas explicitement, mais qui découle logiquement de son analyse. Si l'IA ne configure pas les fondamentaux SEO à la construction, elle ne les maintiendra pas non plus lors des itérations suivantes. Chaque nouveau prompt qui modifie le site peut casser un canonical, supprimer un sitemap, ou introduire un soft 404.\n\nUn outil de monitoring comme Seogard détecte automatiquement ces régressions — une meta description qui disparaît après un déploiement, un canonical qui change, un robots.txt modifié — avant qu'elles n'impactent l'indexation.\n\n## Le vrai problème : la compétence SEO ne s'encode pas dans un prompt\n\nLe constat de Mueller touche un point plus profond que la simple absence de `robots.txt`. Le SEO technique est un système de contraintes interdépendantes. Le `canonical` d'une page dépend de l'architecture d'URL. Le `robots.txt` dépend de la structure des facettes. Le sitemap dépend de la logique d'indexation que vous avez définie.\n\nCes décisions ne sont pas des tâches d'implémentation — ce sont des décisions d'architecture qui requièrent une compréhension du fonctionnement des moteurs de recherche, de votre maillage interne, de votre stratégie de contenu. Un LLM peut écrire le code d'un sitemap dynamique si vous lui demandez. Mais il ne peut pas décider quelles pages méritent d'être dans le sitemap.\n\nLe vibe coding fonctionne remarquablement bien pour le prototypage, le front-end, les fonctionnalités utilisateur. Mais il crée un faux sentiment de complétude. Le site \"a l'air terminé\", donc l'équipe le met en production. Les conséquences SEO n'apparaissent que 4 à 8 semaines plus tard, quand le trafic organique s'effondre et que Search Console affiche des centaines de pages en \"Découverte, non indexée\".\n\nCe phénomène va s'amplifier. Plus les outils IA deviennent capables, plus de sites seront construits par des équipes sans expertise SEO. Et plus le rôle du SEO technique — celui qui audite, configure, et monitore — deviendra critique.\n\nPour les sites qui aspirent à être visibles non seulement dans la recherche classique mais aussi dans les résultats générés par IA, [la construction pour les agents IA](/blog/google-tells-developers-to-build-for-ai-agents-not-just-humans-via-sejournal-mattgsouthern) ajoute une couche de complexité supplémentaire que le vibe coding est encore moins capable de gérer. Et si votre contenu n'est déjà pas crawlable correctement, [il ne sera jamais cité par l'AI Search](/blog/why-ai-search-skips-your-content-and-how-to-diagnose-where-it-s-failing-via-sejournal-jeffrey-coyle).\n\n## Ce qu'il faut retenir\n\nLe vibe coding n'est pas l'ennemi du SEO. Mais il ne fait le travail qu'à moitié, et c'est la moitié visible — celle que le navigateur affiche. La moitié invisible — celle que Googlebot interprète — reste entièrement à votre charge. Chaque site AI-built devrait passer par un audit SEO technique complet avant mise en production, et être surveillé en continu après chaque itération. Les outils IA construisent vite. Mais seul un monitoring permanent — comme celui que propose Seogard — garantit que les fondamentaux SEO survivent à chaque déploiement.","https://seogard.io/blog/google-s-mueller-on-why-ai-built-websites-miss-seo-basics-via-sejournal-mattgsouthern","Actualités SEO","2026-05-11T15:02:42.510Z","2026-05-11","Mueller confirme que les outils IA ne gèrent pas canonicals, sitemaps ni robots.txt. Audit technique complet des failles SEO des sites AI-built.","\u003Cp>John Mueller, Search Advocate chez Google, a posé le diagnostic sans détour : les outils d'IA générative produisent des sites fonctionnels en quelques minutes, mais ignorent systématiquement les fondamentaux techniques du SEO. Pas de \u003Ccode>robots.txt\u003C/code>, pas de \u003Ccode>sitemap.xml\u003C/code>, pas de balises canonical, pas de gestion propre des status codes. Le \"vibe coding\" — cette pratique qui consiste à décrire un site en langage naturel et laisser l'IA le construire — livre du code qui compile, mais qui reste invisible pour les moteurs de recherche.\u003C/p>\n\u003Cp>Ce constat n'est pas une opinion. C'est une observation vérifiable sur la quasi-totalité des projets générés par Bolt, v0, Lovable ou Claude Artifacts. Et les conséquences sur des sites de plusieurs milliers de pages sont dévastatrices.\u003C/p>\n\u003Ch2>Le problème structurel : l'IA optimise pour le navigateur, pas pour le crawler\u003C/h2>\n\u003Cp>Les LLM qui génèrent du code web sont entraînés sur des corpus massifs de code source. Leur objectif d'optimisation : produire du code qui fonctionne visuellement dans un navigateur. Le rendu Googlebot n'a jamais fait partie de leur fonction de loss.\u003C/p>\n\u003Cp>Concrètement, quand vous demandez à un outil comme Bolt de créer un site e-commerce, vous obtenez un SPA React avec du client-side rendering, des routes dynamiques gérées par React Router, et zéro indication pour les robots d'indexation. Le site s'affiche parfaitement dans Chrome. Googlebot, lui, voit une coquille vide.\u003C/p>\n\u003Ch3>L'absence de SSR comme symptôme\u003C/h3>\n\u003Cp>La majorité des sites AI-built utilisent des frameworks SPA (React, Vue) sans configuration SSR. Le code généré ressemble à ceci :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;!\u003C/span>\u003Cspan style=\"color:#85E89D\">DOCTYPE\u003C/span>\u003Cspan style=\"color:#B392F0\"> html\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">html\u003C/span>\u003Cspan style=\"color:#B392F0\"> lang\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"en\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">head\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">meta\u003C/span>\u003Cspan style=\"color:#B392F0\"> charset\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"UTF-8\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> />\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">meta\u003C/span>\u003Cspan style=\"color:#B392F0\"> name\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"viewport\"\u003C/span>\u003Cspan style=\"color:#B392F0\"> content\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"width=device-width, initial-scale=1.0\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> />\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">title\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>MonShop&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">title\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">head\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">body\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">div\u003C/span>\u003Cspan style=\"color:#B392F0\"> id\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"root\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">div\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">script\u003C/span>\u003Cspan style=\"color:#B392F0\"> type\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"module\"\u003C/span>\u003Cspan style=\"color:#B392F0\"> src\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"/src/main.tsx\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">script\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">body\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>C'est le HTML complet que Googlebot reçoit lors du premier fetch. Pas de balise \u003Ccode>&#x3C;meta name=\"description\">\u003C/code>, pas de \u003Ccode>&#x3C;link rel=\"canonical\">\u003C/code>, pas de données structurées, pas de contenu textuel. Tout dépend de l'exécution JavaScript côté client.\u003C/p>\n\u003Cp>Google peut exécuter du JavaScript, mais avec un délai. La \u003Ca href=\"https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics\">documentation officielle de Google sur le JavaScript SEO\u003C/a> rappelle que le rendering se fait dans une \"file d'attente de rendu\" séparée du crawl initial. Sur un site de 8 000 pages produit en vibe coding, cela signifie potentiellement des semaines avant que le contenu soit réellement indexé — si le crawl budget le permet.\u003C/p>\n\u003Cp>Le problème ne se limite pas au SSR. Même sur des sites statiques générés par IA, les éléments SEO critiques sont absents par défaut, simplement parce que personne ne les a demandés dans le prompt.\u003C/p>\n\u003Ch3>Ce que Mueller dit vraiment\u003C/h3>\n\u003Cp>La position de Mueller, \u003Ca href=\"https://www.searchenginejournal.com/googles-mueller-vibe-coding-wont-handle-your-seo-for-you/574237/\">relayée par Search Engine Journal\u003C/a>, se résume en une phrase : les outils d'IA ne font que ce que vous leur demandez explicitement. Si votre prompt dit \"crée un site vitrine pour un cabinet d'architecte\", vous obtenez des composants visuels. Vous n'obtenez pas un \u003Ccode>robots.txt\u003C/code> configuré, un \u003Ccode>sitemap.xml\u003C/code> dynamique, une gestion des canonicals sur les pages paginées, ni des redirections 301 sur les anciennes URLs.\u003C/p>\n\u003Cp>Ce n'est pas un bug. C'est le fonctionnement normal d'un LLM : il résout le problème posé. Le SEO technique n'est jamais \"le problème posé\" par un non-spécialiste.\u003C/p>\n\u003Ch2>Les cinq failles SEO récurrentes des sites AI-built\u003C/h2>\n\u003Cp>Après audit de plusieurs dizaines de sites générés par des outils de vibe coding (Bolt, v0, Lovable, Replit Agent), un pattern émerge. Les mêmes failles reviennent systématiquement.\u003C/p>\n\u003Ch3>1. Absence de robots.txt\u003C/h3>\n\u003Cp>Aucun des outils testés ne génère de fichier \u003Ccode>robots.txt\u003C/code> par défaut. Sur un site Next.js ou Astro classique, ce fichier est souvent configuré manuellement ou via un plugin. Sur un site AI-built, il n'existe tout simplement pas.\u003C/p>\n\u003Cp>L'absence de \u003Ccode>robots.txt\u003C/code> n'empêche pas l'indexation — Googlebot crawle par défaut tout ce qu'il trouve. Mais elle empêche le contrôle du crawl budget. Sur un site e-commerce avec des pages de filtres (couleur, taille, prix), l'absence de \u003Ccode>robots.txt\u003C/code> laisse Googlebot crawler des milliers de combinaisons de paramètres URL sans valeur d'indexation.\u003C/p>\n\u003Cp>Voici un \u003Ccode>robots.txt\u003C/code> minimal qu'aucun outil IA ne génère, mais que tout site de plus de 500 pages devrait avoir :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan>User-agent: *\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>Disallow: /api/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>Disallow: /checkout/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>Disallow: /account/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>Disallow: /search?*\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>Disallow: /*?sort=\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>Disallow: /*?filter=\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>User-agent: GPTBot\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>Disallow: /\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>User-agent: Google-Extended\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>Disallow: /\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan>Sitemap: https://www.monshop.fr/sitemap.xml\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Notez les deux derniers blocs : la gestion des bots IA (GPTBot, Google-Extended) est un sujet en soi que les outils de vibe coding ignorent totalement. Si vous gérez un site dont le contenu propriétaire a de la valeur, \u003Ca href=\"/blog/your-managed-wordpress-might-be-blocking-ai-bots-and-you-can-t-see-it\">ces directives de contrôle des bots IA\u003C/a> deviennent critiques, et Google teste d'ailleurs \u003Ca href=\"/blog/google-is-testing-new-bot-authorization-standard-via-sejournal-martinibuster\">un nouveau standard d'autorisation des bots\u003C/a>.\u003C/p>\n\u003Ch3>2. Pas de sitemap.xml\u003C/h3>\n\u003Cp>Même constat. Les outils IA ne génèrent pas de sitemap. Sur un blog de 30 pages, l'impact est faible — Googlebot trouvera les pages via les liens internes. Sur un catalogue de 12 000 produits avec une arborescence à 4 niveaux de profondeur, l'absence de sitemap signifie que les pages orphelines ou faiblement maillées ne seront jamais découvertes.\u003C/p>\n\u003Ch3>3. Canonicals absents ou incohérents\u003C/h3>\n\u003Cp>C'est probablement la faille la plus dangereuse. Les sites AI-built ne posent jamais de balise \u003Ccode>&#x3C;link rel=\"canonical\">\u003C/code>. Sur un site avec des variantes d'URL (paramètres UTM, filtres, versions HTTP/HTTPS, trailing slashes), Google doit deviner la version canonique. Et Google devine mal, régulièrement.\u003C/p>\n\u003Ch3>4. Meta tags génériques ou manquants\u003C/h3>\n\u003Cp>Quand ils existent, les \u003Ccode>&#x3C;title>\u003C/code> et \u003Ccode>&#x3C;meta description>\u003C/code> sont soit identiques sur toutes les pages, soit générés à partir du nom du composant React. Un audit Screaming Frog typique sur un site AI-built révèle 80 à 95 % de pages avec des titles dupliqués.\u003C/p>\n\u003Ch3>5. Aucune gestion des erreurs HTTP\u003C/h3>\n\u003Cp>Pas de page 404 personnalisée, pas de redirections, pas de gestion des soft 404. Les routes inexistantes retournent souvent un status 200 avec le contenu de la page d'accueil — le pire scénario possible pour l'indexation.\u003C/p>\n\u003Ch2>Scénario concret : migration d'un catalogue e-commerce vers un site AI-built\u003C/h2>\n\u003Cp>Prenons un cas réaliste. Une marque de mobilier DTC (direct-to-consumer) exploite un site Shopify de 4 200 pages (850 produits, 120 collections, le reste en pages CMS et blog). Le trafic organique : 45 000 visites/mois, principalement sur des requêtes mid-tail (\"table basse chêne massif\", \"étagère murale métal noir\").\u003C/p>\n\u003Cp>L'équipe décide de reconstruire le site avec Bolt + Next.js pour gagner en flexibilité. Le prompt initial : \"Crée un site e-commerce de mobilier moderne avec un catalogue produit, des pages collection, un panier et un checkout.\" Bolt livre un site fonctionnel en 3 heures. Design propre, navigation fluide, composants réutilisables.\u003C/p>\n\u003Ch3>Ce que l'audit révèle\u003C/h3>\n\u003Cp>Deux semaines après la mise en production, l'équipe SEO lance un crawl Screaming Frog :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>4 200 URLs crawlées\u003C/strong>, dont 3 800 retournent un status 200 mais avec un \u003Ccode>&#x3C;title>\u003C/code> identique : \"MonMobilier | Accueil\"\u003C/li>\n\u003Cli>\u003Cstrong>0 balise canonical\u003C/strong> sur l'ensemble du site\u003C/li>\n\u003Cli>\u003Cstrong>Aucun \u003Ccode>robots.txt\u003C/code>\u003C/strong> — Screaming Frog découvre 11 400 URLs crawlables en comptant les variantes de filtres\u003C/li>\n\u003Cli>\u003Cstrong>Pas de sitemap.xml\u003C/strong> — Google Search Console affiche \"Sitemap non détecté\"\u003C/li>\n\u003Cli>\u003Cstrong>Toutes les pages produit\u003C/strong> sont rendues en CSR : le HTML source ne contient que le \u003Ccode>&#x3C;div id=\"root\">\u003C/code>\u003C/li>\n\u003Cli>Les anciennes URLs Shopify (\u003Ccode>/products/table-basse-chene\u003C/code>) retournent un 404 au lieu de rediriger vers les nouvelles (\u003Ccode>/catalogue/tables/table-basse-chene-massif\u003C/code>)\u003C/li>\n\u003C/ul>\n\u003Ch3>L'impact en chiffres\u003C/h3>\n\u003Cp>En 6 semaines :\u003C/p>\n\u003Cul>\n\u003Cli>Le trafic organique passe de 45 000 à 8 200 visites/mois\u003C/li>\n\u003Cli>2 100 pages précédemment indexées sont supprimées de l'index (vérifiable dans le rapport \"Pages\" de Search Console)\u003C/li>\n\u003Cli>Les 850 pages produit ne sont toujours pas indexées — elles restent dans la file de rendering JavaScript de Google\u003C/li>\n\u003Cli>Le rapport \"Couverture\" affiche 3 400 URLs en \"Découverte, actuellement non indexée\"\u003C/li>\n\u003C/ul>\n\u003Cp>Ce scénario n'est pas hypothétique. C'est le pattern exact observé sur des dizaines de migrations vers des sites AI-built depuis début 2025.\u003C/p>\n\u003Ch2>Le kit technique de rattrapage : ce que l'IA ne fera pas pour vous\u003C/h2>\n\u003Cp>Corriger un site AI-built pour le SEO revient à ajouter rétroactivement toute la couche technique que l'IA a ignorée. Voici les interventions prioritaires, avec du code prêt à l'emploi.\u003C/p>\n\u003Ch3>Forcer le SSR et injecter les meta tags côté serveur\u003C/h3>\n\u003Cp>Si le site utilise Next.js (le framework le plus fréquemment généré par les outils IA), la correction passe par la migration des composants vers le App Router avec des metadata statiques ou dynamiques.\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// app/catalogue/[slug]/page.tsx\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { Metadata } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'next'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { getProduct } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '@/lib/api'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { notFound } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'next/navigation'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">interface\u003C/span>\u003Cspan style=\"color:#B392F0\"> Props\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">  params\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { \u003C/span>\u003Cspan style=\"color:#FFAB70\">slug\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> string\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">export\u003C/span>\u003Cspan style=\"color:#F97583\"> async\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> generateMetadata\u003C/span>\u003Cspan style=\"color:#E1E4E8\">({ \u003C/span>\u003Cspan style=\"color:#FFAB70\">params\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> }\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#B392F0\"> Props\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#B392F0\"> Promise\u003C/span>\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">Metadata\u003C/span>\u003Cspan style=\"color:#E1E4E8\">> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> product\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> getProduct\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(params.slug)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003Cspan style=\"color:#F97583\">!\u003C/span>\u003Cspan style=\"color:#E1E4E8\">product) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">    notFound\u003C/span>\u003Cspan style=\"color:#E1E4E8\">()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    title: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">`${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">product\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">name\u003C/span>\u003Cspan style=\"color:#9ECBFF\">} — Mobilier design | MonMobilier`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    description: product.metaDescription \u003C/span>\u003Cspan style=\"color:#F97583\">||\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> `${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">product\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">name\u003C/span>\u003Cspan style=\"color:#9ECBFF\">} en ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">product\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">material\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}. Livraison gratuite dès 500€. Fabrication française.`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    alternates: {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      canonical: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">`https://www.monmobilier.fr/catalogue/${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">params\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">slug\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    openGraph: {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      title: product.name,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      description: product.shortDescription,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      images: [{ url: product.imageUrl, width: \u003C/span>\u003Cspan style=\"color:#79B8FF\">1200\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, height: \u003C/span>\u003Cspan style=\"color:#79B8FF\">630\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> }],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">export\u003C/span>\u003Cspan style=\"color:#F97583\"> default\u003C/span>\u003Cspan style=\"color:#F97583\"> async\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> ProductPage\u003C/span>\u003Cspan style=\"color:#E1E4E8\">({ \u003C/span>\u003Cspan style=\"color:#FFAB70\">params\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> }\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#B392F0\"> Props\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> product\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> getProduct\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(params.slug)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003Cspan style=\"color:#F97583\">!\u003C/span>\u003Cspan style=\"color:#E1E4E8\">product) \u003C/span>\u003Cspan style=\"color:#B392F0\">notFound\u003C/span>\u003Cspan style=\"color:#E1E4E8\">()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">main\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      &#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">h1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>{product.name}\u003C/span>\u003Cspan style=\"color:#F97583\">&#x3C;/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">h1\u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {\u003C/span>\u003Cspan style=\"color:#6A737D\">/* Contenu produit rendu côté serveur */\u003C/span>\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    &#x3C;/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">main\u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  )\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Ce code fait trois choses essentielles que l'IA n'a pas faites : il rend la page côté serveur (Googlebot reçoit du HTML complet), il injecte un canonical explicite par page, et il retourne un vrai 404 quand le produit n'existe pas au lieu d'un soft 404.\u003C/p>\n\u003Cp>Pour aller plus loin sur les pièges JavaScript spécifiques au SEO e-commerce, \u003Ca href=\"/blog/5-javascript-seo-lessons-from-top-ecommerce-sites\">les 5 leçons JavaScript SEO tirées de sites e-commerce majeurs\u003C/a> détaillent les patterns à éviter.\u003C/p>\n\u003Ch3>Générer le sitemap.xml dynamiquement\u003C/h3>\n\u003Cp>Next.js App Router permet de générer un sitemap via une route \u003Ccode>app/sitemap.ts\u003C/code>. Voici une implémentation qui couvre un catalogue produit et des pages CMS :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// app/sitemap.ts\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { MetadataRoute } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'next'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { getAllProducts, getAllCollections, getAllBlogPosts } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '@/lib/api'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">export\u003C/span>\u003Cspan style=\"color:#F97583\"> default\u003C/span>\u003Cspan style=\"color:#F97583\"> async\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> sitemap\u003C/span>\u003Cspan style=\"color:#E1E4E8\">()\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#B392F0\"> Promise\u003C/span>\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">MetadataRoute\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">Sitemap\u003C/span>\u003Cspan style=\"color:#E1E4E8\">> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> baseUrl\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'https://www.monmobilier.fr'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> products\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> getAllProducts\u003C/span>\u003Cspan style=\"color:#E1E4E8\">()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> collections\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> getAllCollections\u003C/span>\u003Cspan style=\"color:#E1E4E8\">()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> posts\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> getAllBlogPosts\u003C/span>\u003Cspan style=\"color:#E1E4E8\">()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> productUrls\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> products.\u003C/span>\u003Cspan style=\"color:#B392F0\">map\u003C/span>\u003Cspan style=\"color:#E1E4E8\">((\u003C/span>\u003Cspan style=\"color:#FFAB70\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">=>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> ({\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    url: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">`${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">baseUrl\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}/catalogue/${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">p\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">slug\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    lastModified: \u003C/span>\u003Cspan style=\"color:#F97583\">new\u003C/span>\u003Cspan style=\"color:#B392F0\"> Date\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(p.updatedAt),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    changeFrequency: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'weekly'\u003C/span>\u003Cspan style=\"color:#F97583\"> as\u003C/span>\u003Cspan style=\"color:#F97583\"> const\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    priority: \u003C/span>\u003Cspan style=\"color:#79B8FF\">0.8\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }))\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> collectionUrls\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> collections.\u003C/span>\u003Cspan style=\"color:#B392F0\">map\u003C/span>\u003Cspan style=\"color:#E1E4E8\">((\u003C/span>\u003Cspan style=\"color:#FFAB70\">c\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">=>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> ({\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    url: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">`${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">baseUrl\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}/collections/${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">c\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">slug\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    lastModified: \u003C/span>\u003Cspan style=\"color:#F97583\">new\u003C/span>\u003Cspan style=\"color:#B392F0\"> Date\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(c.updatedAt),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    changeFrequency: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'weekly'\u003C/span>\u003Cspan style=\"color:#F97583\"> as\u003C/span>\u003Cspan style=\"color:#F97583\"> const\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    priority: \u003C/span>\u003Cspan style=\"color:#79B8FF\">0.7\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }))\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> blogUrls\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> posts.\u003C/span>\u003Cspan style=\"color:#B392F0\">map\u003C/span>\u003Cspan style=\"color:#E1E4E8\">((\u003C/span>\u003Cspan style=\"color:#FFAB70\">post\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">=>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> ({\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    url: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">`${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">baseUrl\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}/blog/${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">post\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">slug\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    lastModified: \u003C/span>\u003Cspan style=\"color:#F97583\">new\u003C/span>\u003Cspan style=\"color:#B392F0\"> Date\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(post.publishedAt),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    changeFrequency: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'monthly'\u003C/span>\u003Cspan style=\"color:#F97583\"> as\u003C/span>\u003Cspan style=\"color:#F97583\"> const\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    priority: \u003C/span>\u003Cspan style=\"color:#79B8FF\">0.5\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }))\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    { url: baseUrl, lastModified: \u003C/span>\u003Cspan style=\"color:#F97583\">new\u003C/span>\u003Cspan style=\"color:#B392F0\"> Date\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(), changeFrequency: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'daily'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, priority: \u003C/span>\u003Cspan style=\"color:#79B8FF\">1.0\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    ...\u003C/span>\u003Cspan style=\"color:#E1E4E8\">productUrls,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    ...\u003C/span>\u003Cspan style=\"color:#E1E4E8\">collectionUrls,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    ...\u003C/span>\u003Cspan style=\"color:#E1E4E8\">blogUrls,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  ]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Sur un site de 4 200 pages, ce sitemap permet à Googlebot de découvrir l'intégralité du catalogue sans dépendre du maillage interne — maillage qui, sur un site AI-built, est souvent incomplet.\u003C/p>\n\u003Ch3>Configurer les redirections 301 pour la migration\u003C/h3>\n\u003Cp>Le point que les outils IA ne gèrent jamais : le mapping des anciennes URLs. Lors d'une migration depuis Shopify, chaque ancienne URL doit pointer vers sa nouvelle destination. En Next.js, cela se configure dans \u003Ccode>next.config.js\u003C/code> :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// next.config.js\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">/** \u003C/span>\u003Cspan style=\"color:#F97583\">@type\u003C/span>\u003Cspan style=\"color:#B392F0\"> {import('next').NextConfig}\u003C/span>\u003Cspan style=\"color:#6A737D\"> */\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> nextConfig\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  async\u003C/span>\u003Cspan style=\"color:#B392F0\"> redirects\u003C/span>\u003Cspan style=\"color:#E1E4E8\">() {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">      // Mapping produits Shopify → nouvelle structure\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        source: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/products/:slug'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        destination: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/catalogue/:slug'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        permanent: \u003C/span>\u003Cspan style=\"color:#79B8FF\">true\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#6A737D\">// 301\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">      // Mapping collections Shopify → nouvelle structure\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        source: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/collections/:slug'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        destination: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/collections/:slug'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        permanent: \u003C/span>\u003Cspan style=\"color:#79B8FF\">true\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">      // Pages spécifiques\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        source: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/pages/about'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        destination: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/a-propos'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        permanent: \u003C/span>\u003Cspan style=\"color:#79B8FF\">true\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">      // Catch-all pour les anciennes URLs de blog\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        source: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/blogs/journal/:slug'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        destination: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/blog/:slug'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        permanent: \u003C/span>\u003Cspan style=\"color:#79B8FF\">true\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    ]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  async\u003C/span>\u003Cspan style=\"color:#B392F0\"> headers\u003C/span>\u003Cspan style=\"color:#E1E4E8\">() {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        source: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/:path*'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        headers: [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">            key: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'X-Robots-Tag'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">            value: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'index, follow'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        ],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">        // Bloquer l'indexation des pages de recherche interne\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        source: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/search'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        headers: [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">            key: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'X-Robots-Tag'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">            value: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'noindex, nofollow'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        ],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    ],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">module\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.\u003C/span>\u003Cspan style=\"color:#79B8FF\">exports\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> nextConfig\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Sur un site avec 850 produits, le mapping un-à-un est rarement suffisant. Les slugs changent entre Shopify et la nouvelle structure. La bonne pratique : exporter toutes les URLs Shopify via l'API, mapper chacune manuellement ou via un script, et tester les redirections avec un crawl Screaming Frog en mode \"list\" avant la mise en production.\u003C/p>\n\u003Ch2>Au-delà du code : la checklist d'audit pour tout site AI-built\u003C/h2>\n\u003Cp>Le code ne suffit pas. Avant de mettre en production un site généré par IA, un audit systématique s'impose. Voici la procédure en cinq étapes, avec les outils associés.\u003C/p>\n\u003Ch3>Étape 1 : Valider le rendu Googlebot\u003C/h3>\n\u003Cp>Utilisez l'outil d'inspection d'URL de Google Search Console. Soumettez 5-10 URLs représentatives (page d'accueil, page catégorie, page produit, article de blog, page de résultat de recherche interne). Comparez le HTML rendu avec le code source. Si le contenu principal n'apparaît pas dans le HTML source, vous avez un problème de CSR.\u003C/p>\n\u003Cp>Alternative pour un test rapide : Chrome DevTools > désactivez JavaScript (Settings > Debugger > Disable JavaScript) et rechargez la page. Ce que vous voyez est approximativement ce que Googlebot voit lors du premier fetch.\u003C/p>\n\u003Ch3>Étape 2 : Crawl complet avec Screaming Frog\u003C/h3>\n\u003Cp>Configurez Screaming Frog en mode \"JavaScript rendering\" (Configuration > Spider > Rendering > JavaScript). Lancez un crawl complet. Les métriques critiques à vérifier :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>Titles dupliqués\u003C/strong> : triez par \"Title 1 Duplicate\" dans l'onglet Page Titles\u003C/li>\n\u003Cli>\u003Cstrong>Meta descriptions manquantes\u003C/strong> : filtre \"Missing\" dans l'onglet Meta Description\u003C/li>\n\u003Cli>\u003Cstrong>Canonicals\u003C/strong> : onglet Canonicals > vérifiez que chaque page a un canonical self-referencing\u003C/li>\n\u003Cli>\u003Cstrong>Status codes\u003C/strong> : triez par code de réponse, cherchez les soft 404 (pages retournant un 200 avec un contenu générique)\u003C/li>\n\u003Cli>\u003Cstrong>Pages orphelines\u003C/strong> : croisez les URLs du sitemap avec les URLs découvertes par le crawl\u003C/li>\n\u003C/ul>\n\u003Ch3>Étape 3 : Vérifier les fichiers techniques\u003C/h3>\n\u003Cp>Testez manuellement :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Ccode>https://votre-site.fr/robots.txt\u003C/code> — doit exister et contenir des directives pertinentes\u003C/li>\n\u003Cli>\u003Ccode>https://votre-site.fr/sitemap.xml\u003C/code> — doit exister, être valide XML, et lister toutes les URLs indexables\u003C/li>\n\u003Cli>Soumettez le sitemap dans Google Search Console si ce n'est pas déjà fait\u003C/li>\n\u003C/ul>\n\u003Ch3>Étape 4 : Tester les redirections\u003C/h3>\n\u003Cp>Si vous migrez depuis un ancien site, exportez toutes les URLs indexées (Search Console > Pages > filtrer par \"Indexées\"). Testez chaque URL avec \u003Ccode>curl\u003C/code> ou un crawl Screaming Frog en mode list :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Tester le status code et la destination de redirection\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -sI\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"https://www.monmobilier.fr/products/table-basse-chene\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -E\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"HTTP/|Location:\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Résultat attendu :\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># HTTP/2 301\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># location: https://www.monmobilier.fr/catalogue/table-basse-chene\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Ch3>Étape 5 : Monitoring continu\u003C/h3>\n\u003Cp>C'est le point que Mueller ne mentionne pas explicitement, mais qui découle logiquement de son analyse. Si l'IA ne configure pas les fondamentaux SEO à la construction, elle ne les maintiendra pas non plus lors des itérations suivantes. Chaque nouveau prompt qui modifie le site peut casser un canonical, supprimer un sitemap, ou introduire un soft 404.\u003C/p>\n\u003Cp>Un outil de monitoring comme Seogard détecte automatiquement ces régressions — une meta description qui disparaît après un déploiement, un canonical qui change, un robots.txt modifié — avant qu'elles n'impactent l'indexation.\u003C/p>\n\u003Ch2>Le vrai problème : la compétence SEO ne s'encode pas dans un prompt\u003C/h2>\n\u003Cp>Le constat de Mueller touche un point plus profond que la simple absence de \u003Ccode>robots.txt\u003C/code>. Le SEO technique est un système de contraintes interdépendantes. Le \u003Ccode>canonical\u003C/code> d'une page dépend de l'architecture d'URL. Le \u003Ccode>robots.txt\u003C/code> dépend de la structure des facettes. Le sitemap dépend de la logique d'indexation que vous avez définie.\u003C/p>\n\u003Cp>Ces décisions ne sont pas des tâches d'implémentation — ce sont des décisions d'architecture qui requièrent une compréhension du fonctionnement des moteurs de recherche, de votre maillage interne, de votre stratégie de contenu. Un LLM peut écrire le code d'un sitemap dynamique si vous lui demandez. Mais il ne peut pas décider quelles pages méritent d'être dans le sitemap.\u003C/p>\n\u003Cp>Le vibe coding fonctionne remarquablement bien pour le prototypage, le front-end, les fonctionnalités utilisateur. Mais il crée un faux sentiment de complétude. Le site \"a l'air terminé\", donc l'équipe le met en production. Les conséquences SEO n'apparaissent que 4 à 8 semaines plus tard, quand le trafic organique s'effondre et que Search Console affiche des centaines de pages en \"Découverte, non indexée\".\u003C/p>\n\u003Cp>Ce phénomène va s'amplifier. Plus les outils IA deviennent capables, plus de sites seront construits par des équipes sans expertise SEO. Et plus le rôle du SEO technique — celui qui audite, configure, et monitore — deviendra critique.\u003C/p>\n\u003Cp>Pour les sites qui aspirent à être visibles non seulement dans la recherche classique mais aussi dans les résultats générés par IA, \u003Ca href=\"/blog/google-tells-developers-to-build-for-ai-agents-not-just-humans-via-sejournal-mattgsouthern\">la construction pour les agents IA\u003C/a> ajoute une couche de complexité supplémentaire que le vibe coding est encore moins capable de gérer. Et si votre contenu n'est déjà pas crawlable correctement, \u003Ca href=\"/blog/why-ai-search-skips-your-content-and-how-to-diagnose-where-it-s-failing-via-sejournal-jeffrey-coyle\">il ne sera jamais cité par l'AI Search\u003C/a>.\u003C/p>\n\u003Ch2>Ce qu'il faut retenir\u003C/h2>\n\u003Cp>Le vibe coding n'est pas l'ennemi du SEO. Mais il ne fait le travail qu'à moitié, et c'est la moitié visible — celle que le navigateur affiche. La moitié invisible — celle que Googlebot interprète — reste entièrement à votre charge. Chaque site AI-built devrait passer par un audit SEO technique complet avant mise en production, et être surveillé en continu après chaque itération. Les outils IA construisent vite. Mais seul un monitoring permanent — comme celui que propose Seogard — garantit que les fondamentaux SEO survivent à chaque déploiement.\u003C/p>",null,12,[18,19,20,21,22,23,24],"AI-built websites","SEO technique","vibe coding","John Mueller","canonicals","sitemaps","robots.txt","Sites générés par IA : les fondamentaux SEO que le vibe coding oublie","Mon May 11 2026 15:02:42 GMT+0000 (Coordinated Universal Time)",[28,43,59],{"_id":29,"slug":30,"__v":6,"author":7,"canonical":31,"category":10,"createdAt":32,"date":33,"description":34,"image":15,"imageAlt":15,"readingTime":16,"tags":35,"title":41,"updatedAt":42},"6a041412aa6b273b0c40f181","how-to-build-local-pages-that-win-in-ai-powered-search-via-sejournal-lorenbaker","https://seogard.io/blog/how-to-build-local-pages-that-win-in-ai-powered-search-via-sejournal-lorenbaker","2026-05-13T06:02:58.743Z","2026-05-13","Guide technique pour construire des pages locales qui performent dans les AI Overviews et AI Mode. Schema, SSR, contenu structuré.",[36,37,38,39,40],"local SEO","AI search","pages locales","schema markup","SSR","Pages locales pour l'AI Search : architecture technique","Wed May 13 2026 06:02:58 GMT+0000 (Coordinated Universal Time)",{"_id":44,"slug":45,"__v":6,"author":7,"canonical":46,"category":10,"createdAt":47,"date":48,"description":49,"image":15,"imageAlt":15,"readingTime":50,"tags":51,"title":57,"updatedAt":58},"6a02c291aa6b273b0c2a74f9","the-tech-seo-audit-for-the-ai-search-era-how-to-maximize-your-ai-visibility-via-sejournal-jetoctopus","https://seogard.io/blog/the-tech-seo-audit-for-the-ai-search-era-how-to-maximize-your-ai-visibility-via-sejournal-jetoctopus","2026-05-12T06:02:57.339Z","2026-05-12","Comment adapter votre audit technique SEO aux exigences des AI Overviews, du crawl par les LLMs et du grounding. Méthodes, code et scénarios concrets.",14,[52,53,54,55,56],"tech seo audit","ai search","ai visibility","crawl budget","structured data","Audit SEO technique pour l'ère AI Search : guide avancé","Tue May 12 2026 06:02:57 GMT+0000 (Coordinated Universal Time)",{"_id":60,"slug":61,"__v":6,"author":7,"canonical":62,"category":10,"createdAt":63,"date":48,"description":64,"image":15,"imageAlt":15,"readingTime":16,"tags":65,"title":70,"updatedAt":71},"6a02fac0aa6b273b0c58d096","the-consensus-gap-via-sejournal-kevin-indig","https://seogard.io/blog/the-consensus-gap-via-sejournal-kevin-indig","2026-05-12T10:02:40.519Z","Une marque peut dominer dans un dashboard AI agrégé et être absente de deux moteurs sur trois. Analyse technique du Consensus Gap et méthodes pour le détecter.",[66,37,67,68,69],"consensus gap","LLM visibility","GEO","multi-engine","The Consensus Gap : votre marque visible sur un LLM, invisible sur deux autres","Tue May 12 2026 10:02:40 GMT+0000 (Coordinated Universal Time)"]