Log analysis SEO : décrypter le comportement de Googlebot

Votre Search Console vous dit que 12 000 pages sont "crawlées — actuellement non indexées". Votre sitemap en déclare 18 000. Votre site en contient réellement 25 000. Où est passé Googlebot ? La Search Console donne une vue filtrée et retardée. Les logs serveur, eux, racontent ce qui s'est réellement passé — chaque requête, chaque status code, chaque milliseconde de temps de réponse. C'est la seule source de vérité sur le comportement réel du crawler.

Anatomie d'une ligne de log : ce que Googlebot vous raconte

Chaque hit de Googlebot génère une ligne dans vos access logs. Avant de parler d'analyse, il faut savoir lire ces lignes. Voici un exemple réel au format Apache Combined :

66.249.66.42 - - [05/Apr/2026:14:23:17 +0000] "GET /produits/chaussures-running-homme-asics-gel-nimbus-25 HTTP/2.0" 200 34521 "-" "Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.6422.175 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"

Décomposons les champs exploitables pour le SEO :

  • 66.249.66.42 : IP dans la plage 66.249.64.0/19, confirmée comme appartenant à Google via reverse DNS. C'est le premier filtre pour éliminer les scrapers qui usurpent le user-agent Googlebot.
  • GET /produits/chaussures-running-homme-asics-gel-nimbus-25 : l'URL exacte crawlée. Pas l'URL canonique, pas l'URL indexée — l'URL demandée.
  • HTTP/2.0 : le protocole utilisé. Googlebot supporte HTTP/2 depuis 2020, ce qui a un impact sur la performance du crawl.
  • 200 : le status code retourné. Un guide complet des status codes est indispensable pour interpréter correctement ce champ.
  • 34521 : la taille de la réponse en bytes. Une page produit qui retourne 300 bytes au lieu de 34K ? Probablement une soft 404 ou un SSR cassé.
  • User-agent : contient Nexus 5X, ce qui identifie le crawler mobile. Googlebot crawle en priorité en mode mobile-first depuis mars 2021.

Vérifier l'authenticité de Googlebot

Avant toute analyse, filtrez les faux Googlebot. Un scraper peut facilement envoyer un user-agent Googlebot/2.1. La vérification officielle passe par un reverse DNS suivi d'un forward DNS :

# Étape 1 : reverse DNS sur l'IP
host 66.249.66.42
# Résultat attendu : crawl-66-249-66-42.googlebot.com

# Étape 2 : forward DNS pour confirmer
host crawl-66-249-66-42.googlebot.com
# Résultat attendu : 66.249.66.42

# Script pour filtrer les vrais Googlebot dans un fichier de log
grep -i "googlebot" /var/log/nginx/access.log | \
awk '{print $1}' | sort -u | while read ip; do
  reverse=$(host "$ip" 2>/dev/null | awk '{print $NF}')
  if echo "$reverse" | grep -qE '\.googlebot\.com\.$|\.google\.com\.$'; then
    echo "VERIFIED: $ip -> $reverse"
  else
    echo "FAKE: $ip -> $reverse"
  fi
done

Sur un e-commerce de taille moyenne, il n'est pas rare de constater que 15 à 30 % des hits identifiés "Googlebot" proviennent en réalité de scrapers. Si vous sautez cette étape de vérification, toute votre analyse est faussée.

Extraire les métriques SEO clés depuis les logs

Les logs bruts ne servent à rien sans agrégation. Voici les métriques à extraire et ce qu'elles révèlent.

Fréquence de crawl par section du site

La métrique la plus actionable : combien de fois Googlebot visite chaque section, rapporté au nombre de pages dans cette section. Pour un e-commerce vendant des chaussures avec la structure /produits/, /categories/, /marques/, /blog/, voici comment l'extraire :

# Extraire la distribution de crawl par répertoire de premier niveau
# Prérequis : fichier filtré contenant uniquement les vrais hits Googlebot
awk '{print $7}' googlebot_verified.log | \
  sed 's|\(/[^/]*\)/.*|\1|' | \
  sort | uniq -c | sort -rn | head -20

# Résultat typique pour un e-commerce de 18 000 pages :
#   42381 /produits
#   18904 /categories
#    8211 /marques
#    6102 /blog
#    3847 /compte        <-- problème : section non-indexable crawlée
#    2190 /panier        <-- problème : pages transactionnelles crawlées
#    1847 /recherche     <-- problème : résultats de recherche interne

Ce résultat est typique. Googlebot gaspille du crawl budget sur /compte, /panier et /recherche — des sections qui devraient être bloquées via robots.txt ou retourner un noindex. Les résultats de recherche interne sont un cas classique d'index bloat.

Ratio crawl/indexation

Croisez vos logs avec votre sitemap pour identifier les pages crawlées mais non indexées, et surtout les pages jamais crawlées :

import xml.etree.ElementTree as ET
from collections import Counter

# Charger les URLs du sitemap
tree = ET.parse('sitemap.xml')
ns = {'sm': 'http://www.sitemaps.org/schemas/sitemap/0.9'}
sitemap_urls = set()
for url_elem in tree.findall('.//sm:url/sm:loc', ns):
    # Normaliser : extraire le path sans le domaine
    path = url_elem.text.replace('https://www.monshop.fr', '')
    sitemap_urls.add(path)

# Charger les URLs crawlées par Googlebot (déjà filtrées)
crawled_urls = set()
crawl_counts = Counter()
with open('googlebot_verified.log', 'r') as f:
    for line in f:
        parts = line.split('"')
        if len(parts) >= 2:
            request = parts[1]  # "GET /path HTTP/2.0"
            method_path = request.split()
            if len(method_path) >= 2:
                path = method_path[1].split('?')[0]  # Supprimer query strings
                crawled_urls.add(path)
                crawl_counts[path] += 1

# Analyse
in_sitemap_not_crawled = sitemap_urls - crawled_urls
crawled_not_in_sitemap = crawled_urls - sitemap_urls

print(f"URLs dans le sitemap : {len(sitemap_urls)}")
print(f"URLs crawlées (30 derniers jours) : {len(crawled_urls)}")
print(f"Dans sitemap, jamais crawlées : {len(in_sitemap_not_crawled)}")
print(f"Crawlées mais absentes du sitemap : {len(crawled_not_in_sitemap)}")

# Les pages du sitemap jamais crawlées en 30 jours = problème critique
print("\n--- Pages du sitemap jamais crawlées (échantillon) ---")
for url in list(in_sitemap_not_crawled)[:20]:
    print(f"  {url}")

Ce script révèle un pattern fréquent : des pages déclarées dans le sitemap XML mais jamais visitées par Googlebot en 30 jours. Sur un site de 18 000 pages, trouver 3 000 à 5 000 pages orphelines de crawl n'est pas rare. C'est souvent la cause principale de la non-indexation — un sujet qu'on détaille dans pourquoi Google n'indexe pas vos pages.

Distribution des status codes

# Distribution des status codes pour les hits Googlebot
awk '{print $9}' googlebot_verified.log | sort | uniq -c | sort -rn

# Résultat sain :
#   68412  200
#    2341  301
#     847  304
#     312  404
#      23  500
#       7  503

# Résultat problématique :
#   41203  200
#   18472  301   <-- trop de redirections crawlées
#    8934  302   <-- redirections temporaires suspectes
#    3201  404   <-- trop de 404
#     847  500   <-- erreurs serveur répétées

Un ratio élevé de 301 vs 302 dans vos logs révèle souvent des chaînes de redirections non résolues ou une migration de site mal finalisée. Les erreurs 404 en volume indiquent des liens internes cassés que Googlebot continue de suivre.

Cas concret : un e-commerce de 22 000 pages qui gaspillait 40 % de son crawl budget

Voici un scénario réel (chiffres anonymisés). Un e-commerce mode avec :

  • 22 000 pages produit
  • 1 800 pages catégorie (dont 600 pages de filtres à facettes)
  • 350 pages de contenu éditorial
  • Infrastructure : Nginx + Node.js (Next.js), CDN Cloudflare

Le constat initial

Analyse de 30 jours de logs Nginx (47 Go bruts). Après filtrage des vrais Googlebot uniquement :

Métrique Valeur
Total hits Googlebot/mois 186 000
URLs uniques crawlées 31 400
Pages dans le sitemap 24 150
Pages du sitemap crawlées 14 800 (61 %)
Pages hors sitemap crawlées 16 600

Googlebot crawlait 16 600 URLs qui n'avaient rien à faire dans l'index. En creusant :

  • 8 200 hits sur des URLs de filtres à facettes (/categorie/robes?couleur=rouge&taille=38&tri=prix-asc) — des combinaisons infinies de paramètres non bloquées.
  • 4 100 hits sur /compte/*, /panier/*, /wishlist/* — des sections derrière authentification mais accessibles en GET sans cookie.
  • 2 800 hits sur des URLs avec trailing slash dupliqué (/produits/robe-ete-fleurie/ vs /produits/robe-ete-fleurie).
  • 1 500 hits sur des pages de résultats de recherche interne /search?q=....

Les corrections appliquées

1. Robots.txt mis à jour pour bloquer les facettes et sections non-indexables :

# /robots.txt
User-agent: *
Disallow: /compte/
Disallow: /panier/
Disallow: /wishlist/
Disallow: /search
Disallow: /categorie/*?*couleur=
Disallow: /categorie/*?*taille=
Disallow: /categorie/*?*tri=

Sitemap: https://www.modeshop.fr/sitemap-index.xml

2. Normalisation des trailing slashes via Nginx :

# Redirection 301 : supprimer le trailing slash partout sauf racine
server {
    # ... config existante ...

    # Supprime le trailing slash avec une 301
    rewrite ^(.+)/$ $1 permanent;

    # Bloquer les paramètres de tri dans le crawl (belt and suspenders)
    if ($arg_tri) {
        set $robots_tag "noindex, follow";
    }
    add_header X-Robots-Tag $robots_tag;
}

3. Ajout de rel="canonical" sur toutes les pages filtrées pointant vers la catégorie mère, et vérification que les pages filtrées retournent un header X-Robots-Tag: noindex, follow en complément du robots.txt.

Les résultats après 60 jours

Métrique Avant Après Delta
Hits Googlebot/mois 186 000 178 000 -4 %
URLs uniques crawlées 31 400 21 200 -32 %
Pages du sitemap crawlées 14 800 (61 %) 19 600 (81 %) +32 %
Pages hors sitemap crawlées 16 600 1 600 -90 %
Pages indexées (Search Console) 16 200 20 800 +28 %

Le volume total de crawl a légèrement baissé, mais la couverture des pages utiles est passée de 61 % à 81 %. L'indexation a suivi, mécaniquement. Les 20 % restants non crawlés correspondaient principalement à des pages produit en rupture de stock avec un maillage interne faible — un problème distinct à traiter au niveau de l'architecture du site.

Ce type de diagnostic est impossible sans log analysis. La Search Console vous aurait montré "Crawlée — actuellement non indexée" sans vous dire que Googlebot passait son temps sur des URLs de filtre. Pour plus de contexte sur le crawl budget et son fonctionnement réel, l'analyse de logs est le seul moyen de quantifier le gaspillage.

Outils et pipeline technique pour l'analyse de logs

La stack minimaliste (petits sites, < 50K pages)

Pour un site de quelques milliers de pages, les outils CLI Unix suffisent largement. awk, grep, sort, uniq et quelques scripts Python comme celui montré plus haut couvrent 80 % des besoins.

Screaming Frog Log Analyzer est l'outil desktop le plus accessible. Il importe directement les fichiers de log Apache, Nginx, IIS ou Cloudfront, et produit des rapports préconstruits : fréquence de crawl par URL, distribution des status codes, identification des bots. Limitation principale : il charge tout en RAM, donc au-delà de 10-15 Go de logs, c'est inutilisable sur un laptop standard.

La stack intermédiaire (sites de 10K à 100K pages)

À cette échelle, vous avez besoin d'un pipeline structuré. La combinaison ELK (Elasticsearch, Logstash, Kibana) ou sa variante open source OpenSearch est le standard.

Voici une config Logstash qui parse les logs Nginx et enrichit les données pour l'analyse SEO :

# /etc/logstash/conf.d/googlebot-seo.conf
input {
  file {
    path => "/var/log/nginx/access.log"
    start_position => "beginning"
    sincedb_path => "/var/lib/logstash/sincedb_nginx"
  }
}

filter {
  grok {
    match => {
      "message" => '%{IPORHOST:client_ip} - - \[%{HTTPDATE:timestamp}\] "%{WORD:http_method} %{URIPATH:url_path}(?:%{URIPARAM:url_params})? HTTP/%{NUMBER:http_version}" %{NUMBER:status_code:integer} %{NUMBER:response_size:integer} "%{DATA:referrer}" "%{DATA:user_agent}"'
    }
  }

  # Identifier le type de bot
  if [user_agent] =~ /Googlebot/ {
    mutate { add_field => { "bot_type" => "googlebot" } }

    if [user_agent] =~ /Googlebot-Image/ {
      mutate { replace => { "bot_type" => "googlebot-image" } }
    } else if [user_agent] =~ /Smartphone|Mobile/ {
      mutate { add_field => { "googlebot_device" => "mobile" } }
    } else {
      mutate { add_field => { "googlebot_device" => "desktop" } }
    }
  } else if [user_agent] =~ /bingbot/ {
    mutate { add_field => { "bot_type" => "bingbot" } }
  } else {
    mutate { add_field => { "bot_type" => "other" } }
  }

  # Extraire la section du site depuis l'URL
  grok {
    match => { "url_path" => "^/(?<site_section>[^/]+)" }
    tag_on_failure => ["_root_url"]
  }

  # Supprimer les paramètres pour analyser les URLs canoniques
  mutate {
    add_field => { "url_clean" => "%{url_path}" }
  }

  date {
    match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]
    target => "@timestamp"
  }
}

output {
  if [bot_type] == "googlebot" {
    elasticsearch {
      hosts => ["localhost:9200"]
      index => "googlebot-crawl-%{+YYYY.MM}"
    }
  }
}

Avec cette config, vous obtenez dans Kibana des dashboards temps réel : heatmap de crawl par heure, évolution du taux de 5xx servies à Googlebot, pages les plus crawlées vs les moins crawlées.

BigQuery pour les gros volumes

Google fournit les logs d'exploration via l'API Search Console, mais ils sont limités et agrégés. Pour les sites à fort volume (100K+ pages), exporter vos logs serveur vers BigQuery via un pipeline Cloud Logging (GCP) ou un export S3 → BigQuery (AWS) permet des requêtes SQL sur des mois de données.

-- Top 50 des pages du sitemap jamais crawlées par Googlebot en 90 jours
SELECT s.url
FROM `project.dataset.sitemap_urls` s
LEFT JOIN (
  SELECT DISTINCT url_path
  FROM `project.dataset.googlebot_logs`
  WHERE timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 90 DAY)
    AND bot_verified = TRUE
) g ON s.url = g.url_path
WHERE g.url_path IS NULL
ORDER BY s.lastmod DESC
LIMIT 50;

Patterns avancés : ce que les logs révèlent sur le rendering JavaScript

Pour les sites en JavaScript avec rendu côté client, l'analyse de logs prend une dimension supplémentaire. Googlebot effectue deux passes : un crawl HTML initial, puis un rendering JavaScript via le Web Rendering Service (WRS). Les deux passes génèrent des entrées de log distinctes.

Identifier les problèmes de rendu SSR

Si vous utilisez Next.js, Nuxt ou un autre framework avec SSR, vos logs doivent montrer des réponses de taille cohérente pour Googlebot. Un signal d'alerte classique : des pages qui retournent une réponse de 2-5 Ko (le shell HTML vide) au lieu de 30-80 Ko (la page complètement rendue côté serveur).

# Identifier les pages avec des réponses anormalement petites pour Googlebot
# (probable SSR cassé retournant un shell vide)
awk '$9 == 200 {print $7, $10}' googlebot_verified.log | \
  awk '$2 < 5000 {print $0}' | \
  sort | uniq -c | sort -rn | head -30

# Comparer la taille moyenne des réponses Googlebot vs utilisateurs réels
# pour détecter un cloaking involontaire ou un SSR défaillant
echo "=== Googlebot ==="
awk '$9 == 200 {sum += $10; count++} END {print "Avg response size:", sum/count, "bytes"}' googlebot_verified.log

echo "=== Users ==="
grep -v -i "bot\|crawler\|spider" /var/log/nginx/access.log | \
  awk '$9 == 200 {sum += $10; count++} END {print "Avg response size:", sum/count, "bytes"}'

Si la taille moyenne servie à Googlebot est significativement inférieure à celle servie aux utilisateurs, vous avez un problème de SSR ou de lazy loading qui masque du contenu au crawler.

Corréler les requêtes de ressources statiques

Googlebot demande aussi les fichiers CSS, JS, images et fonts nécessaires au rendering. Si vos logs montrent des 403 ou 404 sur des fichiers .js ou .css critiques, le rendu sera incomplet. Vérifiez que votre robots.txt ne bloque pas ces ressources — un piège classique documenté dans le guide robots.txt.

# Lister les ressources statiques demandées par Googlebot avec erreur
awk '$9 >= 400 && $9 < 500' googlebot_verified.log | \
  grep -E '\.(js|css|woff2?|ttf|svg|json)' | \
  awk '{print $9, $7}' | sort | uniq -c | sort -rn | head -20

Les problèmes de font loading sont fréquemment révélés par cette analyse : Googlebot tente de charger une web font, reçoit un 403 car le CDN bloque par User-Agent ou par Origin header, et le rendu est dégradé.

Automatiser la surveillance : du one-shot au monitoring continu

L'analyse de logs ponctuelle a de la valeur, mais le vrai gain est dans le monitoring continu. Un SSR qui casse à 3h du matin après un déploiement, une règle robots.txt écrasée par un merge malheureux, un CDN qui commence à servir des 503 à Googlebot — ces régressions ne se détectent que si vous surveillez en permanence.

Alertes automatiques avec un script cron

À minima, un script qui tourne toutes les heures et alerte sur les anomalies :

#!/bin/bash
# /opt/scripts/googlebot-monitor.sh
# À exécuter via cron toutes les heures

LOG_FILE="/var/log/nginx/access.log"
ALERT_EMAIL="[email protected]"
THRESHOLD_5XX=50
THRESHOLD_AVG_SIZE=3000

# Compter les 5xx servies à Googlebot dans la dernière heure
FIVE_XX_COUNT=$(awk -v d="$(date -d '1 hour ago' '+%d/%b/%Y:%H')" \
  '$0 ~ d && /Googlebot/ && $9 >= 500 {count++} END {print count+0}' "$LOG_FILE")

# Taille moyenne des réponses 200 servies à Googlebot dans la dernière heure
AVG_SIZE=$(awk -v d="$(date -d '1 hour ago' '+%d/%b/%Y:%H')" \
  '$0 ~ d && /Googlebot/ && $9 == 200 {sum += $10; count++} END {if(count>0) print sum/count; else print 0}' "$LOG_FILE")

if [ "$FIVE_XX_COUNT" -gt "$THRESHOLD_5XX" ]; then
  echo "ALERTE: $FIVE_XX_COUNT erreurs 5xx servies à Googlebot dans la dernière heure" | \
    mail -s "[SEO ALERT] Erreurs 5xx Googlebot" "$ALERT_EMAIL"
fi

if [ "$(echo "$AVG_SIZE < $THRESHOLD_AVG_SIZE" | bc)" -eq 1 ] && [ "$(echo "$AVG_SIZE > 0" | bc)" -eq 1 ]; then
  echo "ALERTE: Taille moyenne des réponses Googlebot = ${AVG_SIZE} bytes (seuil: ${THRESHOLD_AVG_SIZE}). SSR probablement cassé." | \
    mail -s "[SEO ALERT] Réponses Googlebot trop petites" "$ALERT_EMAIL"
fi

Ce genre de script maison fonctionne mais demande de la maintenance. Pour les équipes qui ne veulent pas maintenir une infrastructure de monitoring de logs, un outil comme Seogard détecte automatiquement les régressions de crawlabilité — y compris les changements de status code, les baisses de taille de réponse, et les pages qui disparaissent du crawl — sans avoir à parser les logs manuellement.

Croiser les données avec l'API URL Inspection

Pour aller plus loin, croisez vos données de logs avec l'API URL Inspection de Google. Cela permet de vérifier, pour les pages identifiées comme problématiques dans vos logs, leur statut d'indexation réel côté Google. Une page crawlée avec un 200 mais que l'API retourne comme "URL is not on Google" indique souvent un problème de qualité de contenu, de duplicate, ou de canonical mal configuré.

Les limites de la log analysis — et quand ne pas l'utiliser

L'analyse de logs n'est pas une solution universelle. Quelques cas où elle ne suffit pas, ou où elle peut induire en erreur :

Les CDN masquent les logs d'origine. Si vous utilisez Cloudflare ou un autre CDN avec cache activé, Googlebot peut recevoir des réponses du cache sans que la requête atteigne votre serveur d'origine. Vos logs d'origine ne montrent alors qu'une fraction du crawl réel. Solution : utilisez les logs du CDN (Cloudflare Enterprise Logs, CloudFront access logs) en complément.

Google ne crawle pas que via Googlebot. Le Web Rendering Service effectue des requêtes supplémentaires pour charger des ressources JavaScript. Ces requêtes peuvent ne pas porter le user-agent Googlebot classique — elles passent parfois par des IPs Google différentes.

Le volume ne dit pas tout. Googlebot peut crawler une page 50 fois par mois et ne jamais l'indexer si le contenu est jugé de faible qualité ou dupliqué. La fréquence de crawl n'est pas une métrique de qualité, c'est une métrique de découverte et de freshness.

Les logs ne mesurent pas le rendu. Vous voyez que Googlebot a demandé la page et reçu un 200. Vous ne voyez pas ce que le WRS a rendu après exécution JavaScript. Pour ça, vous avez besoin de tests de rendu séparés (Google Rich Results Test, ou votre propre rendering pipeline avec Puppeteer).

Pour les sites en SPA, la log analysis seule est insuffisante : elle montre les requêtes HTTP mais pas le DOM final rendu. Combinez-la systématiquement avec des tests de rendering et les données de la Search Console.


L'analyse de logs est le microscope du SEO technique. La Search Console est une carte routière approximative ; les logs sont les coordonnées GPS exactes. Pour les sites au-delà de quelques milliers de pages, c'est la seule méthode fiable pour comprendre où Googlebot passe son temps, identifier les gaspillages de crawl budget, et détecter les régressions techniques avant qu'elles n'impactent l'indexation. Mettez en place un pipeline de log analysis — même minimal — et transformez ces données en actions. Un monitoring continu, qu'il soit artisanal ou via un outil comme Seogard, est la différence entre subir les décisions de crawl de Google et les piloter.

Articles connexes

SEO Technique5 avril 2026

HTTPS et SEO : configuration SSL/TLS sans erreurs

Certificat, HSTS, mixed content, chaînes de redirection HTTP→HTTPS : tout ce qui casse votre SEO au-delà du simple cadenas vert.

SEO Technique5 avril 2026

HTTP/2 et HTTP/3 : impact réel sur le crawl et le SEO

HTTP/2 et HTTP/3 accélèrent le crawl et améliorent les Core Web Vitals. Config serveur, diagnostic et impact SEO technique concret.

SEO Technique5 avril 2026

CDN et SEO : configurer Cloudflare sans casser le référencement

Configuration Cloudflare optimale pour le SEO : cache, headers, redirections, et pièges à éviter sur les sites de 500 à 50 000 pages.