SEO pour les sites Astro : le guide complet 2026
Tout ce qu'il faut pour faire remonter un site Astro dans les résultats : métadonnées, sitemaps, données structurées, i18n et Core Web Vitals.
- Astro
- Technical SEO
Astro est l’un des meilleurs frameworks que vous puissiez choisir si la recherche organique compte pour vous — et ce n’est pas un hasard. Toute sa philosophie de conception (livrer du HTML, livrer zéro JavaScript par défaut, rendre au moment du build) s’aligne presque parfaitement avec ce que les moteurs de recherche récompensent réellement. Le site que vous lisez en ce moment même est construit avec Astro : tout ce qui suit a donc été éprouvé sur le terrain, ce n’est pas de la théorie.
Ce guide parcourt toute la surface SEO d’un projet Astro : métadonnées et canonicals, sitemaps et robots, données structurées JSON-LD, routage multilingue, Core Web Vitals, ainsi que les pièges qui vous coûtent discrètement des positions. Chaque section s’accompagne de code réel que vous pouvez coller dans votre propre projet.
Pourquoi Astro est excellent pour le SEO
La plupart des problèmes SEO des sites modernes remontent à une cause racine : la page que le crawler télécharge n’est pas la page que l’utilisateur voit. Une route rendue côté client en React ou Next livre un <div id="root"></div> vide et hydrate le vrai contenu plus tard. Google peut exécuter du JavaScript, mais il le fait lors d’une seconde vague différée, avec un budget limité — consultez notre analyse approfondie sur le JavaScript SEO et le rendu pour comprendre ce qui se passe réellement dans ce pipeline.
Astro contourne tout le problème :
| Préoccupation | SPA typique | Astro (par défaut) |
|---|---|---|
| HTML initial | Coquille vide | Contenu entièrement rendu |
| JavaScript livré | Tout le bundle de l’app | Zéro, sauf si vous l’activez |
| Contenu visible au crawl | Après la vague de rendu | À la première requête |
| Time to first byte | Calcul serveur | Fichier statique depuis le CDN |
L’architecture en îlots (Islands) d’Astro signifie que l’interactivité s’active à la demande, composant par composant. Vous hydratez la seule barre de recherche ou le seul carrousel qui a besoin de JavaScript, et tout le reste demeure du HTML brut, crawlable. La sortie par défaut est statique (SSG), sémantique et immédiatement indexable.
🧑💻 Point de vue développeur : le plus gros gain SEO d’Astro est une non-décision. Vous ne faites rien, et vous obtenez du HTML rendu côté serveur sans bundle client. Les autres frameworks vous obligent à vous battre pour ça.
Métadonnées et canonical
Les balises title, les meta descriptions, les URL canoniques et les balises Open Graph sont le minimum vital. L’erreur que commettent la plupart des équipes consiste à les éparpiller sur les pages, si bien qu’elles finissent par diverger. La solution : un unique layout qui reçoit des props et émet un balisage <head> cohérent partout.
Créez src/layouts/BaseLayout.astro :
---
interface Props {
title: string;
description: string;
image?: string;
}
const { title, description, image = "/og-default.png" } = Astro.props;
// Build an absolute canonical from the current URL + your site origin.
const canonical = new URL(Astro.url.pathname, Astro.site).href;
const ogImage = new URL(image, Astro.site).href;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonical} />
<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={canonical} />
<meta property="og:image" content={ogImage} />
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image" />
</head>
<body>
<slot />
</body>
</html>
Pour que Astro.site se résolve, définissez-la dans astro.config.mjs :
export default defineConfig({
site: "https://example.com",
});
Désormais, chaque page se contente de transmettre les données :
---
import BaseLayout from "../layouts/BaseLayout.astro";
---
<BaseLayout
title="SEO for Astro Sites: The Complete 2026 Guide"
description="Make your Astro site rank with metadata, sitemaps, and more."
>
<h1>...</h1>
</BaseLayout>
💡 Astuce : une canonical auto-référente (la page qui pointe vers sa propre URL propre) est la défense la plus efficace contre les problèmes de contenu dupliqué causés par les chaînes de requête, les paramètres de tracking et les variantes avec/sans barre oblique finale.
Sitemap et robots
Un sitemap indique aux moteurs de recherche quelles URL existent et quand elles ont changé. Astro dispose d’une intégration officielle — installez-la et enregistrez-la :
npx astro add sitemap
Cette commande modifie votre config pour obtenir :
import sitemap from "@astrojs/sitemap";
export default defineConfig({
site: "https://example.com",
integrations: [sitemap()],
});
Au moment du astro build, vous obtenez maintenant sitemap-index.xml ainsi que des sitemaps enfants paginés dans dist/. L’intégration ne fonctionne que si site est défini — cette origine préfixe chaque URL.
Pour robots.txt, oubliez le fichier statique et utilisez un endpoint dynamique afin que l’URL du sitemap reste synchronisée avec votre config. Créez src/pages/robots.txt.ts :
import type { APIRoute } from "astro";
const robots = (sitemapURL: URL) => `
User-agent: *
Allow: /
Sitemap: ${sitemapURL.href}
`.trim();
export const GET: APIRoute = ({ site }) => {
const sitemapURL = new URL("sitemap-index.xml", site);
return new Response(robots(sitemapURL), {
headers: { "Content-Type": "text/plain" },
});
};
⚠️ Attention :
Disallowdans robots.txt bloque le crawl, pas l’indexation. Une URL interdite mais pointée par des liens externes peut toujours apparaître dans les résultats sous forme de simple lien. Pour garder une page hors de l’index, laissez-la être crawlée et ajoutez plutôt<meta name="robots" content="noindex">.
Données structurées (JSON-LD)
Les données structurées sont ce qui vous permet de décrocher des résultats enrichis : signatures d’articles, fils d’Ariane, accordéons de FAQ, notes en étoiles. Google les lit sous forme de JSON-LD dans une balise script. Le pattern propre en Astro consiste à construire l’objet dans le frontmatter et à le sérialiser dans le layout.
Dans BaseLayout.astro, acceptez une prop schema optionnelle et émettez-la avec set:html pour que les guillemets ne soient pas échappés :
---
interface Props {
title: string;
description: string;
schema?: Record<string, unknown>;
}
const { title, description, schema } = Astro.props;
---
<head>
<!-- ...other tags... -->
{schema && (
<script
type="application/ld+json"
set:html={JSON.stringify(schema)}
/>
)}
</head>
Une page d’article de blog transmettrait un objet Article :
---
const schema = {
"@context": "https://schema.org",
"@type": "Article",
headline: "SEO for Astro Sites: The Complete 2026 Guide",
datePublished: "2026-06-21",
author: { "@type": "Person", name: "Your Name" },
};
---
<BaseLayout title="..." description="..." schema={schema}>
💡 Astuce : écrire les objets schema à la main est source d’erreurs. Notre générateur de Schema produit un JSON-LD valide pour les types courants, que vous pouvez coller directement dans la prop. Revérifiez toujours le résultat dans le test des résultats enrichis de Google (Rich Results Test).
Multilingue (i18n)
Si vous servez plusieurs langues, la règle est simple et sans pitié : chaque version linguistique d’une page doit déclarer toutes les autres versions via hreflang, y compris une auto-référence. Commettez une erreur ici et Google servira la mauvaise langue ou traitera les variantes comme des doublons.
Configurez le routage dans astro.config.mjs :
export default defineConfig({
site: "https://example.com",
i18n: {
defaultLocale: "en",
locales: ["en", "fr", "ja"],
routing: { prefixDefaultLocale: true },
},
});
Avec prefixDefaultLocale: true, le contenu vit sous /en/, /fr/, /ja/ — pas de racine ambiguë qui entrerait en concurrence avec un chemin de langue. Émettez ensuite le cluster hreflang dans votre <head> :
---
const locales = ["en", "fr", "ja"];
// Strip the current locale prefix to get the shared path segment.
const path = Astro.url.pathname.replace(/^\/[a-z]{2}/, "");
---
{locales.map((loc) => (
<link
rel="alternate"
hreflang={loc}
href={new URL(`/${loc}${path}`, Astro.site).href}
/>
))}
<link
rel="alternate"
hreflang="x-default"
href={new URL(`/en${path}`, Astro.site).href}
/>
L’entrée x-default indique à Google quelle version afficher lorsqu’aucune langue ne correspond à l’utilisateur. Conservez les traductions sous forme de fichiers parallèles (content/blog/en/post.mdx, content/blog/fr/post.mdx) pour que le calcul de chemin ci-dessus reste trivial.
Core Web Vitals
La sortie statique d’Astro vous donne une longueur d’avance : aucun coût d’hydratation, aucun framework client provoquant des décalages de mise en page, du HTML servi directement depuis un CDN. Cela couvre gratuitement la majeure partie du Largest Contentful Paint (LCP) et de l’Interaction to Next Paint (INP). Les deux choses qui continuent de vous piéger sont les images et les polices.
Utilisez le composant <Image /> intégré d’Astro — il génère des formats modernes, redimensionne et impose des dimensions :
---
import { Image } from "astro:assets";
import hero from "../assets/hero.png";
---
<Image
src={hero}
alt="Descriptive alt text"
width={1200}
height={630}
format="webp"
loading="eager"
/>
Une courte checklist pour rester dans la zone verte :
- Définissez explicitement
width/heightsur chaque image pour éviter les décalages de mise en page (CLS). - Utilisez
loading="eager"pour l’image LCP,lazypour tout ce qui est sous la ligne de flottaison. - Hébergez vous-même les polices et ajoutez
font-display: swappour que le texte s’affiche avant le chargement de la police. - Préchargez l’unique fichier de police le plus important ; ne les préchargez pas tous.
- N’appliquez aucune directive
client:*à du contenu visible au premier rendu.
| Métrique | Ce qu’elle mesure | Comportement par défaut d’Astro |
|---|---|---|
| LCP | Temps de peinture du plus grand élément | Solide — HTML statique, servi par CDN |
| CLS | Stabilité visuelle | Solide si les images ont des dimensions |
| INP | Réactivité aux interactions | Excellent — aucune hydratation par défaut |
Pièges courants
Voici les erreurs qui passent les tests en local et plombent quand même le classement :
- Le contenu
client:onlyest invisible pour les crawlers. Un composantclient:onlyne rend rien côté serveur — il n’y a aucun HTML de repli. Si du contenu important s’y trouve, il ne sera pas indexé. Utilisezclient:load(qui rend toujours côté serveur) ou, mieux, gardez le contenu en.astrobrut. - Incohérence de barre oblique finale. L’option
trailingSlashd’Astro ("always","never","ignore") doit correspondre à la façon dont votre hébergeur sert les fichiers et à ce qu’utilisent vos liens internes. Un décalage produit/pageet/page/comme deux URL distinctes, ce qui divise le link equity. Choisissez-en une, définissez-la dans la config, et faites en sorte que chaque lien interne s’y conforme. - Config
sitemanquante. Sanssitedéfini, les canonicals et le sitemap se cassent silencieusement ou produisent des URL relatives. C’est la cause la plus fréquente d’un sitemap vide ou invalide. - Oublier le
noindexsur les pages pauvres. Les pages d’archives de tags et de pagination n’apportent souvent aucune valeur. Ajoutez-leur une balise metanoindexplutôt que de les laisser diluer votre budget de crawl. - S’appuyer sur les redirections pour la canonicalisation. Une balise canonical est une suggestion ; un 301 est une directive. Pour les vrais doublons (HTTP vs HTTPS, www vs non-www), imposez la redirection au niveau de l’hébergeur ou du CDN — ne vous reposez pas sur la seule balise canonical.
⚠️ Attention : vérifiez toujours avec l’artefact réel, pas avec le serveur de dev. Lancez
astro buildet inspectezdist/— ouvrez le HTML généré et confirmez que votre contenu, vos balises meta et votre JSON-LD sont réellement présents dans la sortie statique.astro devpeut masquer des différences de rendu.
Pour conclure
Astro vous offre une base que la plupart des frameworks vous obligent à construire à la main : du HTML rendu côté serveur, zéro JavaScript par défaut et une sortie statique rapide qu’adorent à la fois les crawlers et les Core Web Vitals. Votre travail consiste à empiler par-dessus les signaux délibérés — un layout unique qui injecte des métadonnées et des canonicals cohérents, un sitemap et un endpoint robots dynamique, du JSON-LD pour les résultats enrichis, des clusters hreflang corrects pour chaque langue, ainsi qu’une gestion rigoureuse des images et des polices.
Faites cela bien et vous aurez éliminé presque toutes les raisons techniques pour lesquelles un moteur de recherche pourrait vous classer plus bas.
Prochaines étapes :
- Construire correctement les fondations : La couche Build
- Comprendre comment les crawlers traitent le JS : JavaScript SEO et rendu
- Générer rapidement un balisage valide : Générateur de Schema