[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fsZtU_e-AMDFQ0b4fphwsrzieC_wu4XJ6VbdmM9kQPhc":3,"$fWMaF-EECTxjDC1QlFr4MzZgGbaLytnX3JUtQuJzds-k":25},{"_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":23,"updatedAt":24},"69f8df45aa6b273b0c01d5b4","google-fixes-search-console-s-year-long-data-logging-issue-well-kind-of",0,"Equipe Seogard","Pendant environ 50 semaines, Search Console a enregistré des données de performance incorrectes. Google a corrigé le bug en mai 2026. Mais l'historique reste tel quel — aucune correction rétroactive. Si vous avez pris des décisions stratégiques basées sur ces données entre mi-2025 et début 2026, vous avez potentiellement travaillé sur des hypothèses fausses.\n\n## Ce que Google a réellement cassé (et corrigé)\n\nLe problème, documenté par [Search Engine Land](https://searchengineland.com/google-fixes-search-consoles-year-long-data-logging-issue-well-kind-of-476442), concerne le logging des données de performance dans l'API et l'interface Search Console. Le bug affectait la manière dont certaines impressions et certains clics étaient attribués aux pages et aux requêtes. Google n'a pas communiqué de détails techniques précis sur la nature exacte du dysfonctionnement — ce qui est un problème en soi.\n\nCe qu'on sait :\n\n- Le bug a duré environ 50 semaines, soit quasiment toute l'année calendaire 2025 et le début de 2026.\n- Les données futures (post-fix) devraient être fiables.\n- Les données historiques ne seront **pas** corrigées. Elles restent dans votre compte telles quelles, faussées.\n- Le bug impactait potentiellement les métriques d'impressions, de clics, de CTR et de position moyenne — les quatre colonnes fondamentales du rapport de performance.\n\n### Pourquoi ce n'est pas anodin\n\nSearch Console est la seule source de données first-party pour les performances organiques Google. Contrairement à des outils tiers qui estiment le trafic (Semrush, Ahrefs, Sistrix), GSC rapporte les données réelles du moteur. Quand cette source est corrompue, c'est l'ensemble de la chaîne de décision SEO qui est compromise :\n\n- Les rapports de performance envoyés aux clients ou au management contenaient des chiffres erronés.\n- Les A/B tests SEO (title tags, meta descriptions) ont potentiellement été évalués sur des données fausses.\n- Les décisions de priorisation de contenu basées sur les impressions sans clics (opportunités de CTR) étaient biaisées.\n- Les analyses de cannibalisation de mots-clés, qui reposent lourdement sur le rapport de requêtes GSC, étaient potentiellement incorrectes.\n\n## Quantifier l'impact : un scénario concret\n\nPrenons un cas réaliste. Un site e-commerce de 12 000 pages produits, générant 800 000 sessions organiques par mois. L'équipe SEO utilise les données GSC pour produire un rapport mensuel de performance et prioriser les optimisations.\n\n### Le problème en chiffres\n\nSi le bug a surestimé les impressions de 15 % sur certaines catégories de requêtes (un scénario plausible pour un bug de logging — Google n'ayant pas confirmé l'amplitude exacte), voici ce que ça donne sur un an :\n\n- **Impressions réelles mensuelles** : 25 millions\n- **Impressions reportées (avec bug)** : 28,75 millions (+15 %)\n- **CTR calculé par l'équipe** : 3,2 % (basé sur les impressions gonflées)\n- **CTR réel** : 3,68 %\n\nL'équipe pensait avoir un problème de CTR sur ses pages catégories et a investi 3 mois à réécrire 200 title tags et meta descriptions. En réalité, le CTR était dans la fourchette normale pour son secteur. Ces 3 mois auraient pu être investis sur l'architecture de liens internes ou la couverture de requêtes long-tail — des chantiers qui attendaient.\n\n### Les décisions polluées\n\nL'équipe a aussi identifié une \"baisse de positionnement\" sur 40 requêtes stratégiques en septembre 2025. Position moyenne passée de 4.2 à 6.8. Une task force a été montée, des contenus ont été réécrits, des backlinks ont été acquis en urgence. Sauf que cette baisse était peut-être un artefact du bug de logging, pas un signal algorithmique réel.\n\nCe scénario n'est pas hypothétique. C'est exactement le type de cascade de décisions erronées qu'un bug de données provoque dans une équipe SEO structurée.\n\n## Comment auditer vos données GSC sur la période impactée\n\nGoogle ne corrigera pas l'historique. C'est à vous de déterminer dans quelle mesure vos données ont été affectées et quelles décisions doivent être réévaluées.\n\n### Croiser GSC avec vos données Analytics\n\nLa première étape est de comparer les clics GSC avec les sessions organiques Google dans votre outil analytics (GA4, Matomo, Plausible, etc.). Ces deux métriques ne sont jamais parfaitement alignées — le filtrage de GSC, le sampling de GA4, les bloqueurs de tracking créent toujours un écart. Mais cet écart devrait être relativement stable dans le temps.\n\nExportez vos données avec l'API GSC et comparez-les mois par mois :\n\n```python\nimport pandas as pd\nfrom google.oauth2.credentials import Credentials\nfrom googleapiclient.discovery import build\n\n# Récupération des données GSC via API\ndef get_gsc_data(service, site_url, start_date, end_date):\n    request = {\n        'startDate': start_date,\n        'endDate': end_date,\n        'dimensions': ['date'],\n        'rowLimit': 25000\n    }\n    response = service.searchanalytics().query(\n        siteUrl=site_url, body=request\n    ).execute()\n    \n    rows = response.get('rows', [])\n    return pd.DataFrame([{\n        'date': row['keys'][0],\n        'clicks': row['clicks'],\n        'impressions': row['impressions'],\n        'ctr': row['ctr'],\n        'position': row['position']\n    } for row in rows])\n\n# Comparer avec GA4 (export BigQuery ou CSV)\ngsc_df = get_gsc_data(service, 'sc-domain:votre-domaine.fr', '2025-05-01', '2026-05-01')\nga4_df = pd.read_csv('ga4_organic_sessions_daily.csv')\n\nmerged = gsc_df.merge(ga4_df, on='date', how='inner')\nmerged['delta_pct'] = ((merged['clicks'] - merged['sessions_organic']) / merged['sessions_organic']) * 100\n\n# Identifier les mois où l'écart dévie de la norme\nbaseline_delta = merged[merged['date'] \u003C '2025-05-01']['delta_pct'].mean()\nmerged['anomaly'] = abs(merged['delta_pct'] - baseline_delta) > 10  # seuil de 10 points\nprint(merged[merged['anomaly']][['date', 'clicks', 'sessions_organic', 'delta_pct']])\n```\n\nSi vous observez une divergence croissante entre clics GSC et sessions GA4 à partir de mi-2025, suivie d'une convergence après le fix, vous tenez votre preuve d'impact.\n\n### Utiliser les logs serveur comme source de vérité\n\nLes logs serveur ne mentent pas. Chaque requête HTTP est enregistrée, indépendamment de tout JavaScript, cookie ou bug d'API Google. Pour les sites à fort volume, c'est la source de vérité ultime.\n\nExtraire les visites Googlebot et les visites organiques réelles depuis vos access logs :\n\n```bash\n# Compter les visites organiques réelles (referer Google, user-agent non-bot)\n# sur un mois donné\nzcat /var/log/nginx/access.log.*.gz | \\\n  grep -i 'referer.*google\\.\\(com\\|fr\\|co\\)' | \\\n  grep -v -i 'googlebot\\|apis-google\\|mediapartners' | \\\n  awk '{print $4}' | \\\n  cut -d: -f1 | \\\n  sed 's/\\[//' | \\\n  sort | uniq -c | sort -rn | head -30\n\n# Comparer le volume de crawl Googlebot sur la même période\nzcat /var/log/nginx/access.log.*.gz | \\\n  grep -i 'googlebot' | \\\n  awk '{print $4}' | \\\n  cut -d: -f1 | \\\n  sed 's/\\[//' | \\\n  sort | uniq -c | sort -rn | head -30\n```\n\nSi le volume de visites organiques réelles (logs) reste stable alors que GSC montrait des variations importantes, le bug est confirmé pour votre site.\n\n### Screaming Frog + exports GSC pour l'audit page par page\n\nPour les sites avec des milliers de pages, une analyse macro ne suffit pas. Vous devez identifier quelles pages et quelles requêtes ont été les plus affectées.\n\nExportez l'intégralité de vos données GSC via l'API (pas via l'interface qui limite à 1000 lignes) en segmentant par page et par requête. Importez ces données dans Screaming Frog via le connecteur API custom ou en CSV dans un tableur :\n\n```python\n# Export granulaire par page + query pour identifier les anomalies\ndef get_gsc_pages_queries(service, site_url, start_date, end_date):\n    all_rows = []\n    start_row = 0\n    \n    while True:\n        request = {\n            'startDate': start_date,\n            'endDate': end_date,\n            'dimensions': ['page', 'query', 'date'],\n            'rowLimit': 25000,\n            'startRow': start_row\n        }\n        response = service.searchanalytics().query(\n            siteUrl=site_url, body=request\n        ).execute()\n        \n        rows = response.get('rows', [])\n        if not rows:\n            break\n            \n        for row in rows:\n            all_rows.append({\n                'page': row['keys'][0],\n                'query': row['keys'][1],\n                'date': row['keys'][2],\n                'clicks': row['clicks'],\n                'impressions': row['impressions'],\n                'ctr': row['ctr'],\n                'position': row['position']\n            })\n        \n        start_row += 25000\n        if len(rows) \u003C 25000:\n            break\n    \n    return pd.DataFrame(all_rows)\n\n# Identifier les pages dont le CTR a \"sauté\" après le fix\ndf = get_gsc_pages_queries(service, 'sc-domain:votre-domaine.fr', '2026-04-01', '2026-05-04')\ndf_pre = get_gsc_pages_queries(service, 'sc-domain:votre-domaine.fr', '2026-03-01', '2026-03-31')\n\n# Comparer CTR moyen par page avant/après fix\nctr_pre = df_pre.groupby('page')['ctr'].mean().reset_index()\nctr_pre.columns = ['page', 'ctr_pre_fix']\nctr_post = df.groupby('page')['ctr'].mean().reset_index()\nctr_post.columns = ['page', 'ctr_post_fix']\n\ncomparison = ctr_pre.merge(ctr_post, on='page')\ncomparison['ctr_shift'] = comparison['ctr_post_fix'] - comparison['ctr_pre_fix']\ncomparison = comparison.sort_values('ctr_shift', ascending=False)\n\n# Les pages avec le plus grand shift positif de CTR post-fix\n# sont celles dont les impressions étaient les plus gonflées\nprint(comparison.head(50))\n```\n\nLes pages qui montrent une hausse brutale de CTR après le fix (sans changement de title/description/contenu) sont celles dont les impressions étaient artificiellement gonflées par le bug.\n\n## Les limites structurelles de Search Console comme source de données\n\nCe bug met en lumière un problème plus profond : la dépendance quasi totale de l'industrie SEO à un outil gratuit, opaque, dont Google contrôle unilatéralement la qualité des données.\n\n### Un historique limité à 16 mois\n\nGSC ne conserve que 16 mois de données. Cela signifie que les données faussées de mi-2025 commenceront à sortir de la fenêtre de rétention d'ici fin 2026. Vous perdrez à la fois la trace du bug et la possibilité de le quantifier rétroactivement.\n\nSi vous n'avez pas encore d'export automatisé de vos données GSC, mettez-le en place maintenant. Des outils comme [Search Analytics for Sheets](https://searchanalyticsforsheets.com/) (add-on Google Sheets), des pipelines BigQuery via l'API, ou des solutions de monitoring comme Seogard qui archivent vos données de performance au-delà de la fenêtre GSC sont indispensables pour ce type de situation.\n\n### Pas de changelog, pas de SLA\n\nGoogle ne fournit aucun SLA (Service Level Agreement) sur la qualité des données Search Console. Il n'existe pas de changelog public des bugs de données. La communication sur ce bug est venue de la communauté SEO et de Search Engine Land, pas d'un bulletin officiel Google.\n\nComparez avec la transparence de la [documentation Google sur le rapport de performance](https://support.google.com/webmasters/answer/7042828) : elle explique les métriques, mais ne mentionne nulle part les limitations de fiabilité ou l'existence de bugs historiques.\n\n### L'anonymisation croissante\n\nCe bug s'ajoute à la tendance de fond : Google anonymise de plus en plus de requêtes dans GSC. Sur beaucoup de sites, 30 à 50 % du trafic organique provient de requêtes que GSC ne montre pas. Le rapport de performance n'a jamais été un reflet exact de la réalité — ce bug l'a simplement rendu encore moins fiable.\n\n## Comment construire un système de monitoring résilient\n\nLa leçon fondamentale n'est pas \"Google a un bug\". C'est que toute source de données unique est un single point of failure.\n\n### Le triangle de vérification\n\nPour chaque métrique SEO critique, vous devriez avoir au minimum deux sources indépendantes qui se recoupent :\n\n| Métrique | Source primaire | Source de vérification |\n|---|---|---|\n| Clics organiques | GSC | GA4 / Matomo (sessions organic) |\n| Impressions | GSC | Données de positionnement (Semrush/Ahrefs) × volume de recherche |\n| Positionnement | GSC | Outil de rank tracking dédié |\n| Pages indexées | GSC (rapport de couverture) | `site:` operator + Screaming Frog crawl |\n| Crawl | GSC (rapport d'exploration) | Logs serveur |\n\nQuand les deux sources divergent significativement, c'est un signal d'alerte. Soit votre site a un problème, soit l'une des sources a un bug. Dans les deux cas, vous devez investiguer — et c'est précisément ce type de divergence qu'un outil de monitoring comme Seogard peut détecter automatiquement, en croisant les données de crawl, d'indexation et de performance.\n\n### Automatiser la détection d'anomalies\n\nNe comptez pas sur une vérification manuelle mensuelle. Les anomalies de données doivent déclencher des alertes automatiques. Un script basique de détection d'anomalie sur vos exports GSC quotidiens :\n\n```python\nimport numpy as np\n\ndef detect_anomaly(series, window=28, threshold=2.5):\n    \"\"\"\n    Détecte les anomalies dans une série temporelle\n    en utilisant un z-score sur une fenêtre glissante.\n    \n    threshold=2.5 correspond à environ 1.2% de faux positifs\n    pour une distribution normale — ajustez selon votre tolérance.\n    \"\"\"\n    rolling_mean = series.rolling(window=window).mean()\n    rolling_std = series.rolling(window=window).std()\n    \n    z_scores = (series - rolling_mean) / rolling_std\n    \n    return z_scores.abs() > threshold\n\n# Application sur le delta clics GSC vs sessions GA4\nmerged['is_anomaly'] = detect_anomaly(merged['delta_pct'], window=28, threshold=2.5)\n\n# Alerter si plus de 3 jours consécutifs d'anomalie\nconsecutive = merged['is_anomaly'].rolling(window=3).sum()\nif (consecutive >= 3).any():\n    # Envoyer une alerte Slack/email\n    alert_dates = merged[consecutive >= 3]['date'].tolist()\n    print(f\"ALERTE: Anomalie de données détectée sur {alert_dates}\")\n```\n\nCe type de détection aurait permis d'identifier le bug GSC en quelques semaines, pas en 50.\n\n## Les décisions à réévaluer maintenant\n\nSi vous êtes Lead SEO ou CTO, voici les actions concrètes à mener cette semaine.\n\n### 1. Identifier les décisions prises entre juin 2025 et avril 2026 basées sur GSC\n\nPassez en revue vos tickets Jira/Linear, vos comptes-rendus de réunion, vos rapports mensuels. Toute décision argumentée par \"les données GSC montrent que...\" doit être réévaluée.\n\n### 2. Recalculer vos baselines\n\nVos baselines de performance (CTR moyen par type de page, impressions par catégorie, position moyenne par cluster de requêtes) sont probablement faussées si elles ont été calculées sur la période du bug. Attendez 4 à 6 semaines de données post-fix pour recalculer des baselines fiables.\n\n### 3. Auditer les contenus modifiés \"en réaction\" à des baisses\n\nSi vous avez modifié des pages parce que GSC montrait une baisse de performance, vérifiez via vos logs serveur et GA4 si cette baisse était réelle. Si elle ne l'était pas, le contenu original était peut-être meilleur que la version \"optimisée\".\n\n### 4. Communiquer avec vos stakeholders\n\nSi vous avez des rapports mensuels ou trimestriels envoyés à des clients ou au management, préparez une note explicative. Les comparaisons year-over-year pour 2026 vs 2025 seront mécaniquement faussées. Mieux vaut prévenir que devoir expliquer pourquoi \"les chiffres n'ont pas de sens\" dans 6 mois.\n\n## Le précédent et ce qu'il signale\n\nCe n'est pas la première fois que GSC présente des problèmes de données. En 2019, un [bug similaire avait affecté les données de couverture d'index](https://developers.google.com/search/blog/2019/07/a-note-on-data-anomalies-in-search). En 2022, des anomalies de données Discover avaient été signalées. Le pattern est toujours le même : découverte tardive, communication minimale, pas de correction rétroactive.\n\nCe qui distingue ce bug, c'est sa durée — près d'un an. C'est suffisamment long pour avoir influencé des stratégies SEO annuelles complètes, des budgets, des recrutements, des arbitrages produit.\n\nL'industrie SEO a un problème de dépendance à des données dont elle ne contrôle ni la production, ni la qualité, ni la rétention. Ce bug devrait être un catalyseur pour investir dans des systèmes de monitoring multi-sources qui ne reposent pas sur la fiabilité d'un seul outil. Le fait de s'appuyer excessivement sur un outil unique est un angle mort technique bien documenté — [un biais qui affecte même les équipes les plus expérimentées](/blog/what-s-the-biggest-technical-seo-blind-spot-from-over-relying-on-tools-ask-an-seo-via-sejournal-helenpollitt1).\n\nLes données post-fix devraient être fiables. Archivez-les dès maintenant, croisez-les avec vos autres sources, et construisez le système de vérification que vous auriez dû avoir depuis un an. La prochaine fois — et il y aura une prochaine fois — vous le saurez en semaines, pas en mois.\n```","https://seogard.io/blog/google-fixes-search-console-s-year-long-data-logging-issue-well-kind-of","Actualités SEO","2026-05-04T18:02:45.906Z","2026-05-04","Google corrige un bug de logging dans Search Console après ~50 semaines. Les données passées restent fausses. Voici comment auditer et compenser l'impact.","\u003Cp>Pendant environ 50 semaines, Search Console a enregistré des données de performance incorrectes. Google a corrigé le bug en mai 2026. Mais l'historique reste tel quel — aucune correction rétroactive. Si vous avez pris des décisions stratégiques basées sur ces données entre mi-2025 et début 2026, vous avez potentiellement travaillé sur des hypothèses fausses.\u003C/p>\n\u003Ch2>Ce que Google a réellement cassé (et corrigé)\u003C/h2>\n\u003Cp>Le problème, documenté par \u003Ca href=\"https://searchengineland.com/google-fixes-search-consoles-year-long-data-logging-issue-well-kind-of-476442\">Search Engine Land\u003C/a>, concerne le logging des données de performance dans l'API et l'interface Search Console. Le bug affectait la manière dont certaines impressions et certains clics étaient attribués aux pages et aux requêtes. Google n'a pas communiqué de détails techniques précis sur la nature exacte du dysfonctionnement — ce qui est un problème en soi.\u003C/p>\n\u003Cp>Ce qu'on sait :\u003C/p>\n\u003Cul>\n\u003Cli>Le bug a duré environ 50 semaines, soit quasiment toute l'année calendaire 2025 et le début de 2026.\u003C/li>\n\u003Cli>Les données futures (post-fix) devraient être fiables.\u003C/li>\n\u003Cli>Les données historiques ne seront \u003Cstrong>pas\u003C/strong> corrigées. Elles restent dans votre compte telles quelles, faussées.\u003C/li>\n\u003Cli>Le bug impactait potentiellement les métriques d'impressions, de clics, de CTR et de position moyenne — les quatre colonnes fondamentales du rapport de performance.\u003C/li>\n\u003C/ul>\n\u003Ch3>Pourquoi ce n'est pas anodin\u003C/h3>\n\u003Cp>Search Console est la seule source de données first-party pour les performances organiques Google. Contrairement à des outils tiers qui estiment le trafic (Semrush, Ahrefs, Sistrix), GSC rapporte les données réelles du moteur. Quand cette source est corrompue, c'est l'ensemble de la chaîne de décision SEO qui est compromise :\u003C/p>\n\u003Cul>\n\u003Cli>Les rapports de performance envoyés aux clients ou au management contenaient des chiffres erronés.\u003C/li>\n\u003Cli>Les A/B tests SEO (title tags, meta descriptions) ont potentiellement été évalués sur des données fausses.\u003C/li>\n\u003Cli>Les décisions de priorisation de contenu basées sur les impressions sans clics (opportunités de CTR) étaient biaisées.\u003C/li>\n\u003Cli>Les analyses de cannibalisation de mots-clés, qui reposent lourdement sur le rapport de requêtes GSC, étaient potentiellement incorrectes.\u003C/li>\n\u003C/ul>\n\u003Ch2>Quantifier l'impact : un scénario concret\u003C/h2>\n\u003Cp>Prenons un cas réaliste. Un site e-commerce de 12 000 pages produits, générant 800 000 sessions organiques par mois. L'équipe SEO utilise les données GSC pour produire un rapport mensuel de performance et prioriser les optimisations.\u003C/p>\n\u003Ch3>Le problème en chiffres\u003C/h3>\n\u003Cp>Si le bug a surestimé les impressions de 15 % sur certaines catégories de requêtes (un scénario plausible pour un bug de logging — Google n'ayant pas confirmé l'amplitude exacte), voici ce que ça donne sur un an :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>Impressions réelles mensuelles\u003C/strong> : 25 millions\u003C/li>\n\u003Cli>\u003Cstrong>Impressions reportées (avec bug)\u003C/strong> : 28,75 millions (+15 %)\u003C/li>\n\u003Cli>\u003Cstrong>CTR calculé par l'équipe\u003C/strong> : 3,2 % (basé sur les impressions gonflées)\u003C/li>\n\u003Cli>\u003Cstrong>CTR réel\u003C/strong> : 3,68 %\u003C/li>\n\u003C/ul>\n\u003Cp>L'équipe pensait avoir un problème de CTR sur ses pages catégories et a investi 3 mois à réécrire 200 title tags et meta descriptions. En réalité, le CTR était dans la fourchette normale pour son secteur. Ces 3 mois auraient pu être investis sur l'architecture de liens internes ou la couverture de requêtes long-tail — des chantiers qui attendaient.\u003C/p>\n\u003Ch3>Les décisions polluées\u003C/h3>\n\u003Cp>L'équipe a aussi identifié une \"baisse de positionnement\" sur 40 requêtes stratégiques en septembre 2025. Position moyenne passée de 4.2 à 6.8. Une task force a été montée, des contenus ont été réécrits, des backlinks ont été acquis en urgence. Sauf que cette baisse était peut-être un artefact du bug de logging, pas un signal algorithmique réel.\u003C/p>\n\u003Cp>Ce scénario n'est pas hypothétique. C'est exactement le type de cascade de décisions erronées qu'un bug de données provoque dans une équipe SEO structurée.\u003C/p>\n\u003Ch2>Comment auditer vos données GSC sur la période impactée\u003C/h2>\n\u003Cp>Google ne corrigera pas l'historique. C'est à vous de déterminer dans quelle mesure vos données ont été affectées et quelles décisions doivent être réévaluées.\u003C/p>\n\u003Ch3>Croiser GSC avec vos données Analytics\u003C/h3>\n\u003Cp>La première étape est de comparer les clics GSC avec les sessions organiques Google dans votre outil analytics (GA4, Matomo, Plausible, etc.). Ces deux métriques ne sont jamais parfaitement alignées — le filtrage de GSC, le sampling de GA4, les bloqueurs de tracking créent toujours un écart. Mais cet écart devrait être relativement stable dans le temps.\u003C/p>\n\u003Cp>Exportez vos données avec l'API GSC et comparez-les mois par mois :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> pandas \u003C/span>\u003Cspan style=\"color:#F97583\">as\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> pd\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> google.oauth2.credentials \u003C/span>\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> Credentials\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> googleapiclient.discovery \u003C/span>\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> build\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Récupération des données GSC via API\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C/span>\u003Cspan style=\"color:#B392F0\"> get_gsc_data\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(service, site_url, start_date, end_date):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    request \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        'startDate'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: start_date,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        'endDate'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: end_date,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        'dimensions'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: [\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'date'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        'rowLimit'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#79B8FF\">25000\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    response \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> service.searchanalytics().query(\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">        siteUrl\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">site_url, \u003C/span>\u003Cspan style=\"color:#FFAB70\">body\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">request\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    ).execute()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    rows \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> response.get(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'rows'\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\"> pd.DataFrame([{\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        'date'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'keys'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">][\u003C/span>\u003Cspan style=\"color:#79B8FF\">0\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        'clicks'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'clicks'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        'impressions'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'impressions'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        'ctr'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ctr'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        'position'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'position'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    } \u003C/span>\u003Cspan style=\"color:#F97583\">for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> row \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> rows])\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Comparer avec GA4 (export BigQuery ou CSV)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">gsc_df \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> get_gsc_data(service, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'sc-domain:votre-domaine.fr'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'2025-05-01'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'2026-05-01'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">ga4_df \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> pd.read_csv(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ga4_organic_sessions_daily.csv'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">merged \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> gsc_df.merge(ga4_df, \u003C/span>\u003Cspan style=\"color:#FFAB70\">on\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'date'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#FFAB70\">how\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'inner'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'delta_pct'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> ((merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'clicks'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">-\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'sessions_organic'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]) \u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'sessions_organic'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]) \u003C/span>\u003Cspan style=\"color:#F97583\">*\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 100\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Identifier les mois où l'écart dévie de la norme\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">baseline_delta \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> merged[merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'date'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">&#x3C;\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '2025-05-01'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">][\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'delta_pct'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">].mean()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'anomaly'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> abs\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'delta_pct'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">-\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> baseline_delta) \u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 10\u003C/span>\u003Cspan style=\"color:#6A737D\">  # seuil de 10 points\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">print\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(merged[merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'anomaly'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]][[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'date'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'clicks'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'sessions_organic'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'delta_pct'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]])\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Si vous observez une divergence croissante entre clics GSC et sessions GA4 à partir de mi-2025, suivie d'une convergence après le fix, vous tenez votre preuve d'impact.\u003C/p>\n\u003Ch3>Utiliser les logs serveur comme source de vérité\u003C/h3>\n\u003Cp>Les logs serveur ne mentent pas. Chaque requête HTTP est enregistrée, indépendamment de tout JavaScript, cookie ou bug d'API Google. Pour les sites à fort volume, c'est la source de vérité ultime.\u003C/p>\n\u003Cp>Extraire les visites Googlebot et les visites organiques réelles depuis vos access logs :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Compter les visites organiques réelles (referer Google, user-agent non-bot)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># sur un mois donné\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">zcat\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> /var/log/nginx/access.log.\u003C/span>\u003Cspan style=\"color:#79B8FF\">*\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.gz\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -i\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'referer.*google\\.\\(com\\|fr\\|co\\)'\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -v\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -i\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'googlebot\\|apis-google\\|mediapartners'\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  awk\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '{print $4}'\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  cut\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -d:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -f1\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  sed\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 's/\\[//'\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  sort\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> uniq\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -rn\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> head\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -30\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Comparer le volume de crawl Googlebot sur la même période\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">zcat\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> /var/log/nginx/access.log.\u003C/span>\u003Cspan style=\"color:#79B8FF\">*\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.gz\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -i\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'googlebot'\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  awk\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '{print $4}'\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  cut\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -d:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -f1\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  sed\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 's/\\[//'\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  sort\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> uniq\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -rn\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> head\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -30\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Si le volume de visites organiques réelles (logs) reste stable alors que GSC montrait des variations importantes, le bug est confirmé pour votre site.\u003C/p>\n\u003Ch3>Screaming Frog + exports GSC pour l'audit page par page\u003C/h3>\n\u003Cp>Pour les sites avec des milliers de pages, une analyse macro ne suffit pas. Vous devez identifier quelles pages et quelles requêtes ont été les plus affectées.\u003C/p>\n\u003Cp>Exportez l'intégralité de vos données GSC via l'API (pas via l'interface qui limite à 1000 lignes) en segmentant par page et par requête. Importez ces données dans Screaming Frog via le connecteur API custom ou en CSV dans un tableur :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Export granulaire par page + query pour identifier les anomalies\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C/span>\u003Cspan style=\"color:#B392F0\"> get_gsc_pages_queries\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(service, site_url, start_date, end_date):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    all_rows \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> []\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    start_row \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 0\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    while\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\">        request \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            'startDate'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: start_date,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            'endDate'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: end_date,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            'dimensions'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: [\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'page'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'query'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'date'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            'rowLimit'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#79B8FF\">25000\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            'startRow'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: start_row\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        response \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> service.searchanalytics().query(\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">            siteUrl\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">site_url, \u003C/span>\u003Cspan style=\"color:#FFAB70\">body\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">request\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        ).execute()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        rows \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> response.get(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'rows'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, [])\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">        if\u003C/span>\u003Cspan style=\"color:#F97583\"> not\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> rows:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">            break\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">            \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">        for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> row \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> rows:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">            all_rows.append({\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                'page'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'keys'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">][\u003C/span>\u003Cspan style=\"color:#79B8FF\">0\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                'query'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'keys'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">][\u003C/span>\u003Cspan style=\"color:#79B8FF\">1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                'date'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'keys'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">][\u003C/span>\u003Cspan style=\"color:#79B8FF\">2\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                'clicks'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'clicks'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                'impressions'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'impressions'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                'ctr'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ctr'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                'position'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: row[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'position'\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\">        start_row \u003C/span>\u003Cspan style=\"color:#F97583\">+=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 25000\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">        if\u003C/span>\u003Cspan style=\"color:#79B8FF\"> len\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(rows) \u003C/span>\u003Cspan style=\"color:#F97583\">&#x3C;\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 25000\u003C/span>\u003Cspan style=\"color:#E1E4E8\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">            break\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> pd.DataFrame(all_rows)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Identifier les pages dont le CTR a \"sauté\" après le fix\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">df \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> get_gsc_pages_queries(service, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'sc-domain:votre-domaine.fr'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'2026-04-01'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'2026-05-04'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">df_pre \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> get_gsc_pages_queries(service, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'sc-domain:votre-domaine.fr'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'2026-03-01'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'2026-03-31'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Comparer CTR moyen par page avant/après fix\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">ctr_pre \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> df_pre.groupby(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'page'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ctr'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">].mean().reset_index()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">ctr_pre.columns \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> [\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'page'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ctr_pre_fix'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">ctr_post \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> df.groupby(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'page'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ctr'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">].mean().reset_index()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">ctr_post.columns \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> [\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'page'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ctr_post_fix'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">comparison \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> ctr_pre.merge(ctr_post, \u003C/span>\u003Cspan style=\"color:#FFAB70\">on\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'page'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">comparison[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ctr_shift'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> comparison[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ctr_post_fix'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">-\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> comparison[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ctr_pre_fix'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">comparison \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> comparison.sort_values(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'ctr_shift'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#FFAB70\">ascending\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\">False\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Les pages avec le plus grand shift positif de CTR post-fix\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># sont celles dont les impressions étaient les plus gonflées\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">print\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(comparison.head(\u003C/span>\u003Cspan style=\"color:#79B8FF\">50\u003C/span>\u003Cspan style=\"color:#E1E4E8\">))\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Les pages qui montrent une hausse brutale de CTR après le fix (sans changement de title/description/contenu) sont celles dont les impressions étaient artificiellement gonflées par le bug.\u003C/p>\n\u003Ch2>Les limites structurelles de Search Console comme source de données\u003C/h2>\n\u003Cp>Ce bug met en lumière un problème plus profond : la dépendance quasi totale de l'industrie SEO à un outil gratuit, opaque, dont Google contrôle unilatéralement la qualité des données.\u003C/p>\n\u003Ch3>Un historique limité à 16 mois\u003C/h3>\n\u003Cp>GSC ne conserve que 16 mois de données. Cela signifie que les données faussées de mi-2025 commenceront à sortir de la fenêtre de rétention d'ici fin 2026. Vous perdrez à la fois la trace du bug et la possibilité de le quantifier rétroactivement.\u003C/p>\n\u003Cp>Si vous n'avez pas encore d'export automatisé de vos données GSC, mettez-le en place maintenant. Des outils comme \u003Ca href=\"https://searchanalyticsforsheets.com/\">Search Analytics for Sheets\u003C/a> (add-on Google Sheets), des pipelines BigQuery via l'API, ou des solutions de monitoring comme Seogard qui archivent vos données de performance au-delà de la fenêtre GSC sont indispensables pour ce type de situation.\u003C/p>\n\u003Ch3>Pas de changelog, pas de SLA\u003C/h3>\n\u003Cp>Google ne fournit aucun SLA (Service Level Agreement) sur la qualité des données Search Console. Il n'existe pas de changelog public des bugs de données. La communication sur ce bug est venue de la communauté SEO et de Search Engine Land, pas d'un bulletin officiel Google.\u003C/p>\n\u003Cp>Comparez avec la transparence de la \u003Ca href=\"https://support.google.com/webmasters/answer/7042828\">documentation Google sur le rapport de performance\u003C/a> : elle explique les métriques, mais ne mentionne nulle part les limitations de fiabilité ou l'existence de bugs historiques.\u003C/p>\n\u003Ch3>L'anonymisation croissante\u003C/h3>\n\u003Cp>Ce bug s'ajoute à la tendance de fond : Google anonymise de plus en plus de requêtes dans GSC. Sur beaucoup de sites, 30 à 50 % du trafic organique provient de requêtes que GSC ne montre pas. Le rapport de performance n'a jamais été un reflet exact de la réalité — ce bug l'a simplement rendu encore moins fiable.\u003C/p>\n\u003Ch2>Comment construire un système de monitoring résilient\u003C/h2>\n\u003Cp>La leçon fondamentale n'est pas \"Google a un bug\". C'est que toute source de données unique est un single point of failure.\u003C/p>\n\u003Ch3>Le triangle de vérification\u003C/h3>\n\u003Cp>Pour chaque métrique SEO critique, vous devriez avoir au minimum deux sources indépendantes qui se recoupent :\u003C/p>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Métrique\u003C/th>\n\u003Cth>Source primaire\u003C/th>\n\u003Cth>Source de vérification\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>Clics organiques\u003C/td>\n\u003Ctd>GSC\u003C/td>\n\u003Ctd>GA4 / Matomo (sessions organic)\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Impressions\u003C/td>\n\u003Ctd>GSC\u003C/td>\n\u003Ctd>Données de positionnement (Semrush/Ahrefs) × volume de recherche\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Positionnement\u003C/td>\n\u003Ctd>GSC\u003C/td>\n\u003Ctd>Outil de rank tracking dédié\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Pages indexées\u003C/td>\n\u003Ctd>GSC (rapport de couverture)\u003C/td>\n\u003Ctd>\u003Ccode>site:\u003C/code> operator + Screaming Frog crawl\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Crawl\u003C/td>\n\u003Ctd>GSC (rapport d'exploration)\u003C/td>\n\u003Ctd>Logs serveur\u003C/td>\n\u003C/tr>\n\u003C/tbody>\n\u003C/table>\n\u003Cp>Quand les deux sources divergent significativement, c'est un signal d'alerte. Soit votre site a un problème, soit l'une des sources a un bug. Dans les deux cas, vous devez investiguer — et c'est précisément ce type de divergence qu'un outil de monitoring comme Seogard peut détecter automatiquement, en croisant les données de crawl, d'indexation et de performance.\u003C/p>\n\u003Ch3>Automatiser la détection d'anomalies\u003C/h3>\n\u003Cp>Ne comptez pas sur une vérification manuelle mensuelle. Les anomalies de données doivent déclencher des alertes automatiques. Un script basique de détection d'anomalie sur vos exports GSC quotidiens :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> numpy \u003C/span>\u003Cspan style=\"color:#F97583\">as\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> np\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C/span>\u003Cspan style=\"color:#B392F0\"> detect_anomaly\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(series, window\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\">28\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, threshold\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\">2.5\u003C/span>\u003Cspan style=\"color:#E1E4E8\">):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"\"\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    Détecte les anomalies dans une série temporelle\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    en utilisant un z-score sur une fenêtre glissante.\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    threshold=2.5 correspond à environ 1.2% de faux positifs\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    pour une distribution normale — ajustez selon votre tolérance.\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"\"\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    rolling_mean \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> series.rolling(\u003C/span>\u003Cspan style=\"color:#FFAB70\">window\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">window).mean()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    rolling_std \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> series.rolling(\u003C/span>\u003Cspan style=\"color:#FFAB70\">window\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">window).std()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    z_scores \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (series \u003C/span>\u003Cspan style=\"color:#F97583\">-\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> rolling_mean) \u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> rolling_std\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> z_scores.abs() \u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> threshold\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Application sur le delta clics GSC vs sessions GA4\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'is_anomaly'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> detect_anomaly(merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'delta_pct'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">], \u003C/span>\u003Cspan style=\"color:#FFAB70\">window\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\">28\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#FFAB70\">threshold\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\">2.5\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Alerter si plus de 3 jours consécutifs d'anomalie\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">consecutive \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> merged[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'is_anomaly'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">].rolling(\u003C/span>\u003Cspan style=\"color:#FFAB70\">window\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\">3\u003C/span>\u003Cspan style=\"color:#E1E4E8\">).sum()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (consecutive \u003C/span>\u003Cspan style=\"color:#F97583\">>=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 3\u003C/span>\u003Cspan style=\"color:#E1E4E8\">).any():\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">    # Envoyer une alerte Slack/email\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    alert_dates \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> merged[consecutive \u003C/span>\u003Cspan style=\"color:#F97583\">>=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 3\u003C/span>\u003Cspan style=\"color:#E1E4E8\">][\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'date'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">].tolist()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">    print\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#F97583\">f\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"ALERTE: Anomalie de données détectée sur \u003C/span>\u003Cspan style=\"color:#79B8FF\">{\u003C/span>\u003Cspan style=\"color:#E1E4E8\">alert_dates\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Ce type de détection aurait permis d'identifier le bug GSC en quelques semaines, pas en 50.\u003C/p>\n\u003Ch2>Les décisions à réévaluer maintenant\u003C/h2>\n\u003Cp>Si vous êtes Lead SEO ou CTO, voici les actions concrètes à mener cette semaine.\u003C/p>\n\u003Ch3>1. Identifier les décisions prises entre juin 2025 et avril 2026 basées sur GSC\u003C/h3>\n\u003Cp>Passez en revue vos tickets Jira/Linear, vos comptes-rendus de réunion, vos rapports mensuels. Toute décision argumentée par \"les données GSC montrent que...\" doit être réévaluée.\u003C/p>\n\u003Ch3>2. Recalculer vos baselines\u003C/h3>\n\u003Cp>Vos baselines de performance (CTR moyen par type de page, impressions par catégorie, position moyenne par cluster de requêtes) sont probablement faussées si elles ont été calculées sur la période du bug. Attendez 4 à 6 semaines de données post-fix pour recalculer des baselines fiables.\u003C/p>\n\u003Ch3>3. Auditer les contenus modifiés \"en réaction\" à des baisses\u003C/h3>\n\u003Cp>Si vous avez modifié des pages parce que GSC montrait une baisse de performance, vérifiez via vos logs serveur et GA4 si cette baisse était réelle. Si elle ne l'était pas, le contenu original était peut-être meilleur que la version \"optimisée\".\u003C/p>\n\u003Ch3>4. Communiquer avec vos stakeholders\u003C/h3>\n\u003Cp>Si vous avez des rapports mensuels ou trimestriels envoyés à des clients ou au management, préparez une note explicative. Les comparaisons year-over-year pour 2026 vs 2025 seront mécaniquement faussées. Mieux vaut prévenir que devoir expliquer pourquoi \"les chiffres n'ont pas de sens\" dans 6 mois.\u003C/p>\n\u003Ch2>Le précédent et ce qu'il signale\u003C/h2>\n\u003Cp>Ce n'est pas la première fois que GSC présente des problèmes de données. En 2019, un \u003Ca href=\"https://developers.google.com/search/blog/2019/07/a-note-on-data-anomalies-in-search\">bug similaire avait affecté les données de couverture d'index\u003C/a>. En 2022, des anomalies de données Discover avaient été signalées. Le pattern est toujours le même : découverte tardive, communication minimale, pas de correction rétroactive.\u003C/p>\n\u003Cp>Ce qui distingue ce bug, c'est sa durée — près d'un an. C'est suffisamment long pour avoir influencé des stratégies SEO annuelles complètes, des budgets, des recrutements, des arbitrages produit.\u003C/p>\n\u003Cp>L'industrie SEO a un problème de dépendance à des données dont elle ne contrôle ni la production, ni la qualité, ni la rétention. Ce bug devrait être un catalyseur pour investir dans des systèmes de monitoring multi-sources qui ne reposent pas sur la fiabilité d'un seul outil. Le fait de s'appuyer excessivement sur un outil unique est un angle mort technique bien documenté — \u003Ca href=\"/blog/what-s-the-biggest-technical-seo-blind-spot-from-over-relying-on-tools-ask-an-seo-via-sejournal-helenpollitt1\">un biais qui affecte même les équipes les plus expérimentées\u003C/a>.\u003C/p>\n\u003Cp>Les données post-fix devraient être fiables. Archivez-les dès maintenant, croisez-les avec vos autres sources, et construisez le système de vérification que vous auriez dû avoir depuis un an. La prochaine fois — et il y aura une prochaine fois — vous le saurez en semaines, pas en mois.\u003C/p>\n\u003Cpre>\u003Ccode>\u003C/code>\u003C/pre>",null,12,[18,19,20,21,22],"google","search console","données SEO","monitoring","bug GSC","Search Console : un an de données faussées, et Google ne corrigera rien","Mon May 04 2026 18:02:45 GMT+0000 (Coordinated Universal Time)",[26,41,57],{"_id":27,"slug":28,"__v":6,"author":7,"canonical":29,"category":10,"createdAt":30,"date":31,"description":32,"image":15,"imageAlt":15,"readingTime":16,"tags":33,"title":39,"updatedAt":40},"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é.",[34,35,36,37,38],"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":42,"slug":43,"__v":6,"author":7,"canonical":44,"category":10,"createdAt":45,"date":46,"description":47,"image":15,"imageAlt":15,"readingTime":48,"tags":49,"title":55,"updatedAt":56},"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,[50,51,52,53,54],"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":58,"slug":59,"__v":6,"author":7,"canonical":60,"category":10,"createdAt":61,"date":46,"description":62,"image":15,"imageAlt":15,"readingTime":16,"tags":63,"title":68,"updatedAt":69},"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.",[64,35,65,66,67],"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)"]