L'essentiel, au
- 2 Mo : pour la recherche, Googlebot ne lit que les 2 premiers Mo d'une page HTML, mesurés décompressés.
- CSS et JavaScript : chaque fichier a la même limite, à part.
- Pour vérifier : 6 scripts à coller dans la console de votre navigateur, ci-dessous.
Ce que dit Google sur la limite de 2 Mo
Sa page sur Googlebot a été mise à jour le 3 février 2026. Elle le dit en une phrase : « Googlebot crawls the first 2MB of a supported file type, and the first 64MB of a PDF file. »
| Fichier | Limite lue |
|---|---|
| Page HTML | 2 premiers Mo, décompressés |
| Chaque CSS ou JavaScript | 2 Mo chacun, récupérés à part |
| 64 premiers Mo | |
| Images et vidéos | Robots à part, limites propres |
La compression gzip ou Brotli n'y change rien : Google compte le poids décompressé. Au-delà de la limite, il ignore la suite, sans avertissement.
Avant cette mise à jour, la page annonçait 15 Mo. Google ne dit pas si 2 Mo valent 2 000 000 ou 2 097 152 octets : les scripts prennent le plus bas.
Faut-il s'inquiéter pour votre site ?
Pour la plupart des sites, non. Voici ce que donne le premier script sur trois pages réelles :
- 160 Koaccueil de sk-web.fr : 8 % de la limite (34 Ko transférés compressés)
- 221 Kosite WordPress d'un restaurant que j'ai réalisé
- 15,7 Monorme HTML du WHATWG, en une page : Google n'en lirait que 13 %
Sur sk-web.fr, plus de la moitié de ce poids est la feuille de style (94 Ko). Elle est écrite dans la page, pour un affichage plus rapide.
Ce qui fait grossir une page jusqu'à la limite :
- des images écrites dans le HTML, en base64 ou en SVG recopié ;
- de grosses données JSON ajoutées par un framework JavaScript ;
- une liste interminable d'un seul bloc : catalogue, archives, commentaires.
Avant de coller un script dans la console
- Ouvrez la page à vérifier dans Chrome, Edge, Firefox ou Safari.
- Ouvrez la console : F12, onglet Console. Raccourcis : Ctrl+Maj+J dans Chrome et Edge (Cmd+Option+J sur Mac), Ctrl+Maj+K dans Firefox.
- Dans Safari : activez les fonctionnalités pour les développeurs (Réglages, onglet Avancés), puis Cmd+Option+C.
- Copiez un script avec son bouton, collez-le dans la console et appuyez sur Entrée.
Au premier collage, le navigateur peut demander de taper une phrase d'autorisation (dans Chrome : « allow pasting »). C'est une protection contre les arnaques : ne collez jamais un script que vous ne comprenez pas.
Ces scripts ne font que lire. Ils ne modifient rien et n'envoient rien ailleurs. Les scripts 1, 3 et 4 téléchargent une copie de la page, sans vos cookies, comme Googlebot.
Script 1 : le poids du HTML que Google télécharge
Il mesure le poids décompressé de la page et le compare aux 2 Mo. Il détaille ce qui est écrit dans le HTML : scripts, styles, SVG, images en base64. Au-delà de la limite, il compte les liens et les titres perdus.
// Poids du HTML brut, tel que Googlebot le télécharge, comparé à la limite de 2 Mo
(async () => {
const LIMITE = 2000000; // 2 Mo comptés au plus bas : Google ne dit pas s'il compte 1 000 ou 1 024 octets par Ko
const ko = n => (n / 1000).toLocaleString('fr-FR', { maximumFractionDigits: 1 }) + ' Ko';
const reponse = await fetch(location.href, { credentials: 'omit', cache: 'no-store' });
const octets = new Uint8Array(await reponse.arrayBuffer()); // déjà décompressé par le navigateur
const html = new TextDecoder().decode(octets);
const poids = re => (html.match(re) || []).reduce((total, bloc) => total + new TextEncoder().encode(bloc).length, 0);
console.log(`HTML brut, non compressé : ${ko(octets.length)}, soit ${(100 * octets.length / LIMITE).toLocaleString('fr-FR', { maximumFractionDigits: 1 })} % de la limite de 2 Mo.`);
const chargement = performance.getEntriesByType('navigation')[0];
if (chargement && chargement.encodedBodySize) {
console.log(chargement.encodedBodySize < chargement.decodedBodySize
? `Au chargement, le serveur en a envoyé ${ko(chargement.encodedBodySize)} compressés : la limite porte sur la version non compressée.`
: `Au chargement, le serveur l'a envoyé sans compression (${ko(chargement.encodedBodySize)}).`);
}
console.table({
'Scripts écrits dans la page': ko(poids(/<script\b[^>]*>[\s\S]*?<\/script>/gi)),
'Styles écrits dans la page': ko(poids(/<style\b[^>]*>[\s\S]*?<\/style>/gi)),
'Images SVG écrites dans la page': ko(poids(/<svg\b[\s\S]*?<\/svg>/gi)),
'Images en base64 (data:)': ko(poids(/data:[\w.+-]+\/[\w.+-]+;base64,[\w+\/=]+/g)),
});
if (octets.length > LIMITE) {
const coupe = new TextDecoder().decode(octets.slice(LIMITE));
const compte = re => (coupe.match(re) || []).length.toLocaleString('fr-FR');
console.warn(`Google ignore les ${ko(octets.length - LIMITE)} qui suivent le 2 000 000e octet : ${compte(/<a\s/gi)} liens et ${compte(/<h[1-6]\b/gi)} titres perdus. Début de la partie ignorée :`);
console.log(coupe.slice(0, 300));
}
})();
Sur l'accueil de sk-web.fr, il affiche : « HTML brut, non compressé : 159,9 Ko, soit 8 % de la limite de 2 Mo. »
Script 2 : les fichiers CSS et JavaScript
Chaque fichier CSS et JavaScript a sa propre limite de 2 Mo. Un JavaScript coupé ne s'exécute pas : si la page en dépend, Google risque de ne pas voir son contenu. Le script liste ces fichiers et leur poids décompressé.
// Fichiers CSS et JavaScript chargés par la page : Google lit chacun séparément, avec la même limite de 2 Mo
(() => {
const LIMITE = 2000000;
const ko = n => (n / 1000).toLocaleString('fr-FR', { maximumFractionDigits: 1 }) + ' Ko';
const pasUneImageNiUnePolice = r => !/\.(woff2?|ttf|otf|eot|png|jpe?g|gif|webp|avif|svg|ico)([?#]|$)/i.test(r.name);
const fichiers = performance.getEntriesByType('resource').filter(r =>
r.initiatorType === 'script' || /\.(m?js|css)([?#]|$)/i.test(r.name) ||
(r.initiatorType === 'link' && pasUneImageNiUnePolice(r)));
console.table(fichiers.map(r => ({
fichier: r.name.split(/[?#]/)[0].split('/').slice(-2).join('/'),
'non compressé': r.decodedBodySize ? ko(r.decodedBodySize) : 'inconnu (autre domaine)',
'au-delà de 2 Mo': r.decodedBodySize > LIMITE ? 'OUI : Google ne lit que le début' : '',
})));
const trop = fichiers.filter(r => r.decodedBodySize > LIMITE).length;
console.log(trop ? `${trop} fichier(s) dépassent 2 Mo.` : `${fichiers.length} fichier(s) CSS et JavaScript, aucun ne dépasse 2 Mo (parmi ceux qui sont mesurables).`);
})();
Pour un fichier d'un autre domaine, le navigateur ne donne pas toujours la taille : la colonne affiche « inconnu ». L'onglet Réseau des outils de développement, lui, la donne.
Script 3 : ce qui existe sans JavaScript
Google lit d'abord le HTML brut, puis exécute le JavaScript plus tard. Sa documentation parle d'une file d'attente de « quelques secondes, mais cela peut prendre plus longtemps ». Et tous les robots ne savent pas exécuter JavaScript.
Le texte présent dès le HTML brut est donc le plus sûr. Le script compare les mots du HTML brut à ceux de la page affichée. Il liste les liens et titres ajoutés par JavaScript.
// Ce que contient la page avant JavaScript (HTML brut), comparé à la page affichée
(async () => {
const reponse = await fetch(location.href, { credentials: 'omit', cache: 'no-store' });
const brut = new DOMParser().parseFromString(await reponse.text(), 'text/html');
const baseBrut = new URL(brut.querySelector('base[href]')?.getAttribute('href') || reponse.url, reponse.url).href;
const mots = doc => {
const corps = doc.body.cloneNode(true);
corps.querySelectorAll('script, style, noscript, template').forEach(e => e.remove());
return (corps.textContent.match(/[\p{L}\p{N}]+/gu) || []).length;
};
const liens = (doc, base) => new Set([...doc.querySelectorAll('a[href]')].map(a => {
try { return new URL(a.getAttribute('href'), base).href; } catch (e) { return a.getAttribute('href'); }
}));
const titres = doc => new Set([...doc.querySelectorAll('h1, h2, h3')].map(h => h.textContent.trim().replace(/\s+/g, ' ')));
const motsBrut = mots(brut), motsAffiches = mots(document);
console.log(`Mots dans le HTML brut : ${motsBrut.toLocaleString('fr-FR')}. Dans la page affichée : ${motsAffiches.toLocaleString('fr-FR')}. Part présente sans JavaScript : ${Math.round(100 * motsBrut / Math.max(motsAffiches, 1))} %.`);
const liensBrut = liens(brut, baseBrut), titresBrut = titres(brut);
const ajouts = [
...[...liens(document, document.baseURI)].filter(l => !liensBrut.has(l)).map(l => ({ type: 'lien', valeur: l })),
...[...titres(document)].filter(t => !titresBrut.has(t)).map(t => ({ type: 'titre', valeur: t })),
];
console.log(ajouts.length ? `${ajouts.length} lien(s) ou titre(s) n'existent qu'après JavaScript :` : 'Aucun lien ni titre ajouté par JavaScript.');
if (ajouts.length) console.table(ajouts);
})();
Sur mes articles, il trouve les liens du sommaire, ajoutés en JavaScript : sans conséquence, ce sont des ancres internes. Si votre menu ou vos titres n'existent qu'après JavaScript, c'est un vrai sujet.
Script 4 : les balises que Google lit en premier
Il relit le HTML brut et affiche ce qui décide de l'indexation :
| Balise | Le piège à repérer |
|---|---|
| Code HTTP, X-Robots-Tag | Un « noindex » caché dans la réponse du serveur |
| Meta robots | Un « noindex » oublié après la mise en ligne |
| Title, meta description | Coupés à l'affichage selon la largeur d'écran |
| Canonique | Une autre adresse : Google préférera celle-là |
| Langue, H1, hreflang, JSON-LD | Absents, en double, ou JSON invalide |
// Les balises que Google lit en premier, dans le HTML brut (et l'en-tête X-Robots-Tag du serveur)
(async () => {
const reponse = await fetch(location.href, { credentials: 'omit', cache: 'no-store' });
const doc = new DOMParser().parseFromString(await reponse.text(), 'text/html');
const base = new URL(doc.querySelector('base[href]')?.getAttribute('href') || reponse.url, reponse.url).href;
const texte = e => e.textContent.trim().replace(/\s+/g, ' ');
const titre = texte(doc.querySelector('title') || doc.createElement('title'));
const description = doc.querySelector('meta[name="description" i]')?.getAttribute('content')?.trim() || '';
const canonique = doc.querySelector('link[rel="canonical" i]')?.getAttribute('href');
const urlCanonique = canonique ? new URL(canonique, base).href : '';
const robots = [...doc.querySelectorAll('meta[name="robots" i], meta[name="googlebot" i]')];
const h1 = [...doc.querySelectorAll('h1')];
const jsonld = [...doc.querySelectorAll('script[type="application/ld+json"]')].map(s => {
try { const d = JSON.parse(s.textContent); return [].concat(d['@graph'] || d).map(x => x['@type']).join(', '); }
catch (e) { return 'JSON invalide'; }
});
console.table({
'Code HTTP': reponse.status + (reponse.redirected ? ` (après redirection vers ${reponse.url})` : ''),
'En-tête X-Robots-Tag': reponse.headers.get('x-robots-tag') || 'absent',
'Balise meta robots': robots.map(m => `${m.getAttribute('name')} = ${m.getAttribute('content')}`).join(' | ') || 'absente : indexable par défaut',
'Title': titre ? `${titre} (${titre.length} caractères)` : 'ABSENT',
'Meta description': description ? `${description} (${description.length} caractères)` : 'absente',
'Canonique': urlCanonique ? urlCanonique + (urlCanonique === reponse.url ? ' (cette page)' : ' (AUTRE URL que cette page)') : 'absente',
'Langue (lang)': doc.documentElement.getAttribute('lang') || 'ABSENTE',
'Titres H1': `${h1.length} : ${h1.map(texte).join(' | ')}`,
'Versions linguistiques (hreflang)': doc.querySelectorAll('link[rel="alternate"][hreflang]').length,
'Données structurées (JSON-LD)': jsonld.join(' ; ') || 'aucune',
});
})();
Si votre site n'apparaît pas du tout dans Google, lisez aussi les causes fréquentes d'un site absent de Google.
Script 5 : les liens que Google peut suivre
Selon sa documentation, Google ne suit en général qu'une balise <a> avec un href. Un <span> cliquable ou un lien en JavaScript risquent d'être ignorés. Pour une image cliquable, son texte alternatif sert de texte du lien.
Le script compte les liens explorables et liste ceux à revoir : sans href, en « javascript: », vides ou sans intitulé. Un lien sans intitulé est aussi un défaut d'accessibilité (critère 6.2 du RGAA).
// Les liens que Google peut suivre, et ceux qu'il risque de ne pas suivre
(() => {
const n = x => x.toLocaleString('fr-FR');
const intitule = a => (a.textContent.trim() || a.getAttribute('aria-label') || a.querySelector('img[alt]')?.getAttribute('alt') || '').replace(/\s+/g, ' ').slice(0, 60);
const liens = [...document.querySelectorAll('a')];
const aRevoir = [];
liens.forEach(a => {
const href = a.getAttribute('href');
let probleme = '';
if (href === null) probleme = 'pas de href : Google peut ne pas le suivre';
else if (/^\s*javascript:/i.test(href)) probleme = 'href en javascript: : Google peut ne pas le suivre';
else if (href.trim() === '' || href.trim() === '#') probleme = 'href vide ou # : ne mène nulle part';
else if (!intitule(a)) probleme = 'aucun texte ni alt : lien sans intitulé';
if (probleme) aRevoir.push({ lien: intitule(a) || a.outerHTML.slice(0, 60), href: href ?? '', probleme });
});
document.querySelectorAll('[onclick]:not(a):not(button):not(input):not(label), span[href], div[href], [role="link"]:not(a)').forEach(e =>
aRevoir.push({ lien: (e.textContent.trim() || e.outerHTML).replace(/\s+/g, ' ').slice(0, 60), href: e.getAttribute('href') || '', probleme: `<${e.tagName.toLowerCase()}> cliquable : Google peut ne pas le suivre` }));
const explorables = liens.filter(a => /^https?:$/.test(a.protocol) && a.getAttribute('href')?.trim() && !/^\s*#/.test(a.getAttribute('href')));
const internes = explorables.filter(a => a.hostname === location.hostname).length;
const nofollow = explorables.filter(a => /\bnofollow\b/i.test(a.rel)).length;
console.log(`${n(explorables.length)} liens explorables vers d'autres pages : ${n(internes)} internes, ${n(explorables.length - internes)} externes, dont ${n(nofollow)} en nofollow. ${n(aRevoir.length)} élément(s) à revoir.`);
if (aRevoir.length) console.table(aRevoir);
})();
Script 6 : les images
Trois vérifications en une fois :
- Texte alternatif : un
altabsent est un défaut d'accessibilité (critère 1.1 du RGAA). Google s'en sert aussi pour comprendre l'image. - Dimensions : sans
widthetheight, la page bouge au chargement (indicateur CLS). web.dev conseille de toujours les indiquer. - Chargement différé en haut de page : une image en
loading="lazy"arrive plus tard et retarde souvent le LCP.
// Images : texte alternatif, dimensions, chargement différé dans le premier écran
(() => {
const hauteurEcran = window.innerHeight;
const images = [...document.images].filter(img => img.getBoundingClientRect().width > 0); // images affichées
const lignes = images.map(img => {
const dansLePremierEcran = img.getBoundingClientRect().top + window.scrollY < hauteurEcran;
return {
image: (img.currentSrc || img.src).split(/[?#]/)[0].split('/').pop().slice(0, 50),
alt: !img.hasAttribute('alt') ? 'ABSENT' : img.alt.trim() === '' ? '(vide : image décorative)' : img.alt.slice(0, 50),
'width et height': img.hasAttribute('width') && img.hasAttribute('height') ? 'oui' : 'NON',
'premier écran': dansLePremierEcran ? 'oui' : '',
'chargement différé': img.loading === 'lazy' ? (dansLePremierEcran ? 'OUI : à retirer' : 'oui') : '',
};
});
const compte = test => lignes.filter(test).length;
console.log(`${lignes.length} images affichées : ${compte(l => l.alt === 'ABSENT')} sans attribut alt, ${compte(l => l['width et height'] === 'NON')} sans dimensions, ${compte(l => l['chargement différé'].startsWith('OUI'))} en chargement différé dans le premier écran.`);
console.table(lignes);
})();
« Premier écran » = la hauteur de votre fenêtre. Pour un mobile, activez la simulation d'appareil (Ctrl+Maj+M dans Chrome), rechargez, relancez. Les images de fond en CSS ne sont pas listées.
Ce que ces scripts ne voient pas
- Le fichier robots.txt : une page bloquée par ce fichier n'est pas explorée du tout. Ouvrez l'adresse votredomaine.fr/robots.txt pour le lire.
- La réponse faite à Googlebot : un pare-feu ou une version réservée aux robots peut lui servir une autre page qu'à vous.
- Le rendu de Google : le script 3 compare avec votre navigateur, pas avec celui de Google.
Pour voir la page telle que Google la reçoit, utilisez l'inspection d'URL de la Search Console. Cliquez sur « Tester l'URL active », puis « Afficher la page testée ». Vous obtenez le code HTML et une capture d'écran ; « Plus d'infos » liste les ressources chargées et la console JavaScript.
En bref
- Googlebot lit les 2 premiers Mo du HTML, mesurés décompressés.
- Chaque fichier CSS et JavaScript a sa propre limite de 2 Mo.
- La plupart des pages en sont loin : l'accueil de sk-web.fr pèse 160 Ko.
- Pour voir ce que Google a reçu : Search Console, « Tester l'URL active ».
- Googlebot, Google Search Central, limites de taille : 2 Mo par fichier, 64 Mo par PDF, données non compressées (mise à jour du 3 février 2026)
- Principes de base du référencement JavaScript, Google Search Central, exploration, file de rendu et indexation
- Rendre les liens explorables, Google Search Central, balise <a> avec href, texte alternatif des images cliquables
- Liens de titre, Google Search Central, pas de limite de longueur, troncature selon la largeur de l'écran
- Extraits et meta description, Google Search Central, même règle pour la meta description
- Outil d'inspection d'URL, aide Search Console, tester l'URL active et afficher la page testée
- Protection contre le self-XSS, blog Chrome for Developers, avertissement au premier collage dans la console
- Bonnes pratiques pour Google Images, Google Search Central, rôle du texte alternatif
- Optimiser le CLS, web.dev, dimensions des images
- Chargement différé et LCP, web.dev, images du premier écran
- RGAA 4.1.2, critères et tests, DINUM, critères 1.1 (images) et 6.2 (intitulé des liens)