Pour automatiser un reporting SEO avec lâAPI Google Search Console, on interroge chaque jour la mĂ©thode searchanalytics.query sur une journĂ©e de donnĂ©es, avec les dimensions utiles (date, requĂȘte, page, pays, appareil), on pagine par blocs de 25 000 lignes, puis on stocke le rĂ©sultat dans une base ou un tableur qui alimente le tableau de bord. LâaccĂšs passe par OAuth 2.0, le plus souvent avec un compte de service ajoutĂ© Ă la propriĂ©tĂ©.
- Ă quoi sert lâAPI : dĂ©passer les 1 000 lignes de lâinterface, historiser au-delĂ de seize mois et croiser Search Console avec dâautres sources.
- Méthode clé :
POST âŠ/sites/{siteUrl}/searchAnalytics/queryavec dates, dimensions, filtres, type et limite. - Limites Ă connaĂźtre : 25 000 lignes par rĂ©ponse, 50 000 lignes par jour et par type de recherche, quotas par minute et quota de charge.
- Bonne pratique : une journĂ©e par requĂȘte, un stockage brut, des comparaisons calculĂ©es en aval.
- Outil : le générateur ci-dessous construit le payload et contrÎle sa cohérence, sans jamais demander de clé ni de secret.
Ă quoi sert lâAPI Search Console par rapport Ă lâinterface ?
LâAPI ne contient pas de donnĂ©es « en plus » : elle donne accĂšs aux mĂȘmes mesures que le rapport Performances (clics, impressions, CTR, position moyenne), avec davantage de lignes et sans action manuelle. Sa valeur tient Ă lâautomatisation et au stockage.
| CritĂšre | Interface | API Search Analytics |
|---|---|---|
| Lignes par tableau | 1 000 affichĂ©es et exportĂ©es | JusquâĂ 25 000 par requĂȘte, pagination possible |
| Historique | 16 mois glissants | MĂȘme fenĂȘtre ; illimitĂ© si vous stockez |
| Combinaison de dimensions | Un onglet Ă la fois, filtres manuels | Plusieurs dimensions croisĂ©es dans une mĂȘme requĂȘte |
| Filtres | Contient, ne contient pas, regex | equals, contains, notContains, notEquals, includingRegex, excludingRegex |
| Automatisation | Aucune | Planifiable (cron, Apps Script, orchestrateur) |
| Croisement avec dâautres donnĂ©es | Manuel | Direct en base : CRM, GA4, catalogue, positions |
Pour un diagnostic ponctuel, comme une chute des clics dans Search Console, lâinterface reste plus rapide. LâAPI devient rentable dĂšs quâune analyse doit ĂȘtre rĂ©pĂ©tĂ©e chaque semaine ou portĂ©e sur des milliers de pages.
Anatomie dâune requĂȘte searchAnalytics.query
La requĂȘte est un POST vers https://www.googleapis.com/webmasters/v3/sites/{siteUrl}/searchAnalytics/query, oĂč siteUrl est encodĂ© : sc-domain:exemple.fr pour une propriĂ©tĂ© de domaine, https://www.exemple.fr/ pour une propriĂ©tĂ© prĂ©fixe dâURL. Le corps JSON accepte les paramĂštres suivants, tels que dĂ©crits dans la documentation de rĂ©fĂ©rence.
| ParamĂštre | RĂŽle | Valeurs et contraintes |
|---|---|---|
startDate, endDate | Période, bornes incluses | AAAA-MM-JJ, en heure du Pacifique ; obligatoires |
dimensions | Regroupement des lignes | query, page, country, device, searchAppearance, date, hour |
type | Type de recherche | web (défaut), image, video, news, discover, googleNews |
dimensionFilterGroups | Filtres | Groupes en and ; opérateurs equals, contains, notContains, notEquals, includingRegex, excludingRegex (syntaxe RE2) |
aggregationType | Mode de calcul | auto, byPage, byProperty, byNewsShowcasePanel |
rowLimit, startRow | Pagination | 1 à 25 000 (défaut 1 000) ; décalage à partir de 0 |
dataState | Fraßcheur | final (défaut), all (inclut les données récentes), hourly_all (avec la dimension hour) |
Les dimensions, une par une
- query : la requĂȘte saisie. Les requĂȘtes anonymisĂ©es par Google pour protĂ©ger la vie privĂ©e nâapparaissent pas en ligne, mĂȘme si elles comptent dans les totaux.
- page : lâURL canonique affichĂ©e dans le rĂ©sultat. CroisĂ©e avec
query, câest la vue la plus utile pour dĂ©tecter une cannibalisation entre pages, mais aussi la plus coĂ»teuse. - country : code pays ISO 3166-1 alpha-3 (
fra,bel,che). - device :
DESKTOP,MOBILEouTABLET. - date : indispensable pour historiser ; les jours sans données sont omis.
- hour : vue horaire des données fraßches, à combiner avec
dataState: hourly_all. - searchAppearance : type dâapparence dans les rĂ©sultats ; Google recommande de lâinterroger seul pour lister les valeurs, puis de filtrer dessus.
Agrégation par page ou par propriété
Avec byProperty, une recherche oĂč deux de vos pages apparaissent compte une impression pour le site ; avec byPage, chaque page compte la sienne. Les totaux diffĂšrent donc lĂ©gitimement. Lorsquâon regroupe ou filtre par page, lâagrĂ©gation se fait par page. Choisissez un mode et ne mĂ©langez jamais deux modes dans une mĂȘme sĂ©rie historique.
Les dimensions choisies déterminent le niveau de détail et le volume de lignes renvoyées.
Authentification et propriété : donner accÚs sans exposer de secret
- Projet Google Cloud : activez la Google Search Console API dans un projet dédié au reporting.
- Compte de service : créez-le pour une collecte serveur sans interaction. Sa clé JSON est un secret : stockez-la hors du répertoire public, jamais dans un dépÎt de code, et limitez les droits du fichier.
- AccĂšs Ă la propriĂ©tĂ© : dans Search Console, ParamĂštres âș Utilisateurs et autorisations, ajoutez lâadresse e-mail du compte de service avec un accĂšs restreint, suffisant pour la lecture.
- Portée OAuth : demandez
https://www.googleapis.com/auth/webmasters.readonly. La portĂ©e en Ă©criture nâest utile que pour gĂ©rer sitemaps ou propriĂ©tĂ©s. - Alternative sans serveur : un script Google Apps Script liĂ© Ă un Google Sheets peut sâauthentifier avec le compte de lâutilisateur, Ă condition de dĂ©clarer les portĂ©es dans le manifeste.
Ne collez jamais une clĂ© de compte de service dans un outil en ligne, un tableur partagĂ© ou un prompt dâIA. Le gĂ©nĂ©rateur de cette page ne demande aucun identifiant : il produit seulement la structure de la requĂȘte.
GĂ©nĂ©rateur de requĂȘte Search Console API
Choisissez la pĂ©riode, les dimensions, les filtres, le type de recherche et la limite. Lâoutil affiche la configuration en langage clair, le payload JSON prĂȘt Ă envoyer, un exemple dâappel et les alertes de cohĂ©rence (dimension horaire sans hourly_all, plage supĂ©rieure Ă seize mois, limite hors bornesâŠ). Il fonctionne entiĂšrement dans le navigateur.
Composez une requĂȘte searchAnalytics.query (dimensions, filtres, type, agrĂ©gation, pagination) et copiez le JSON et la commande curl, sans saisir aucun identifiant.
Exemples de requĂȘtes : PHP, Python et Apps Script
Exemple 1 : payload quotidien par page et par requĂȘte
{
"startDate": "2026-10-15",
"endDate": "2026-10-15",
"dimensions": ["date", "page", "query"],
"type": "web",
"rowLimit": 25000,
"startRow": 0
}
Exemple 2 : pages dâun rĂ©pertoire sur mobile en France
{
"startDate": "2026-09-01",
"endDate": "2026-09-30",
"dimensions": ["page"],
"dimensionFilterGroups": [{
"groupType": "and",
"filters": [
{"dimension": "page", "operator": "includingRegex", "expression": "^https://www\\.exemple\\.fr/blog/"},
{"dimension": "country", "operator": "equals", "expression": "fra"},
{"dimension": "device", "operator": "equals", "expression": "MOBILE"}
]
}],
"rowLimit": 5000
}
Exemple 3 : PHP avec la bibliothĂšque cliente Google
Le site Devsource et une grande partie des sites vitrines tournent en PHP : la bibliothĂšque officielle google/apiclient, installĂ©e avec Composer, gĂšre lâauthentification du compte de service.
<?php
require __DIR__ . '/vendor/autoload.php';
$client = new Google\Client();
// Fichier hors du répertoire public, lisible uniquement par le serveur.
$client->setAuthConfig('/chemin/prive/gsc-service-account.json');
$client->addScope(Google\Service\SearchConsole::WEBMASTERS_READONLY);
$service = new Google\Service\SearchConsole($client);
$day = (new DateTimeImmutable('-3 days'))->format('Y-m-d');
$request = new Google\Service\SearchConsole\SearchAnalyticsQueryRequest();
$request->setStartDate($day);
$request->setEndDate($day);
$request->setDimensions(['date', 'page', 'query']);
$request->setRowLimit(25000);
$startRow = 0;
do {
$request->setStartRow($startRow);
$rows = $service->searchanalytics->query('sc-domain:exemple.fr', $request)->getRows() ?? [];
foreach ($rows as $row) {
[$date, $page, $query] = $row->getKeys();
// Insérer $date, $page, $query, $row->getClicks(), $row->getImpressions(),
// $row->getCtr(), $row->getPosition() dans la table historisée.
}
$startRow += 25000;
} while (count($rows) === 25000);
Exemple 4 : Python pour une base de données
from google.oauth2 import service_account
from googleapiclient.discovery import build
SCOPES = ["https://www.googleapis.com/auth/webmasters.readonly"]
creds = service_account.Credentials.from_service_account_file(
"/chemin/prive/gsc-service-account.json", scopes=SCOPES)
service = build("searchconsole", "v1", credentials=creds)
def fetch_day(site, day, search_type="web"):
rows, start = [], 0
while True:
body = {"startDate": day, "endDate": day, "type": search_type,
"dimensions": ["date", "page", "query"],
"rowLimit": 25000, "startRow": start}
batch = service.searchanalytics().query(siteUrl=site, body=body).execute().get("rows", [])
rows.extend(batch)
if len(batch) < 25000:
return rows
start += 25000
Exemple 5 : Google Sheets avec Apps Script
Dans le manifeste appsscript.json, déclarez les portées https://www.googleapis.com/auth/webmasters.readonly, https://www.googleapis.com/auth/script.external_request et https://www.googleapis.com/auth/spreadsheets.currentonly, puis :
function importSearchConsole() {
const site = encodeURIComponent('sc-domain:exemple.fr');
const day = Utilities.formatDate(new Date(Date.now() - 3 * 864e5), 'America/Los_Angeles', 'yyyy-MM-dd');
const response = UrlFetchApp.fetch(
'https://www.googleapis.com/webmasters/v3/sites/' + site + '/searchAnalytics/query', {
method: 'post',
contentType: 'application/json',
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() },
payload: JSON.stringify({ startDate: day, endDate: day, dimensions: ['page'], rowLimit: 5000 }),
muteHttpExceptions: true
});
if (response.getResponseCode() !== 200) throw new Error(response.getContentText());
const rows = (JSON.parse(response.getContentText()).rows || [])
.map(r => [day, r.keys[0], r.clicks, r.impressions, r.ctr, r.position]);
if (rows.length) SpreadsheetApp.getActive().getSheetByName('GSC')
.getRange(SpreadsheetApp.getActive().getSheetByName('GSC').getLastRow() + 1, 1, rows.length, 6).setValues(rows);
}
Un déclencheur temporel quotidien suffit. Au-delà de quelques dizaines de milliers de lignes par jour, un tableur atteint ses limites : passez à une base de données.
Limites, quotas et Ă©carts avec lâinterface
| Limite | Valeur documentée | Conséquence pratique |
|---|---|---|
| Lignes par rĂ©ponse | 25 000 au maximum | Paginer avec startRow jusquâĂ une rĂ©ponse incomplĂšte ou vide |
| Lignes exposées | 50 000 par jour et par type de recherche, triées par clics | Sur un gros site, la trÚs longue traßne reste invisible : interrogez une journée à la fois |
| RequĂȘtes par minute | 1 200 par site et 1 200 par utilisateur ; 40 000 par projet (30 millions par jour) | Espacer les appels lors dâun rattrapage dâhistorique |
| Quota de charge | MesurĂ© sur 10 minutes et sur 24 heures | Les requĂȘtes groupĂ©es ou filtrĂ©es par page et requĂȘte sur de longues pĂ©riodes coĂ»tent le plus |
| Fraßcheur | Données généralement disponibles aprÚs 2 à 3 jours (final) | Collecter J-3, ou utiliser dataState all en signalant les jours incomplets |
| FenĂȘtre | 16 mois | Stocker pour comparer au-delĂ |
Trois Ă©carts avec lâinterface sont normaux : les requĂȘtes anonymisĂ©es (prĂ©sentes dans les totaux, absentes des lignes), la diffĂ©rence entre agrĂ©gation par page et par propriĂ©tĂ©, et la coupure due aux limites de lignes. Pour vĂ©rifier votre chaĂźne, comparez le total dâune requĂȘte sans dimension (ou avec la seule dimension date) au graphique de lâinterface : ils doivent concorder.
Automatiser le reporting : collecte, stockage et tableau de bord
Choisir la destination
| Solution | Idéale pour | Avantages | Limites | Complexité | Recommandation |
|---|---|---|---|---|---|
| Google Sheets + Apps Script | Petit site, suivi par page | Aucun serveur, partage simple | Volume et temps dâexĂ©cution limitĂ©s | Faible | DĂ©marrage ou site vitrine |
| Base de donnĂ©es (MySQL, PostgreSQL) | Site Ă©ditorial ou e-commerce | Historique illimitĂ©, requĂȘtes SQL, croisement CRM | HĂ©bergement et maintenance du script | Moyenne | Choix par dĂ©faut dâun reporting durable |
| Export groupĂ© natif vers BigQuery | TrĂšs gros sites | Export quotidien sans code, sans limite de lignes de lâAPI | CoĂ»ts BigQuery, compĂ©tences SQL | Moyenne Ă Ă©levĂ©e | Au-delĂ des limites de lâAPI |
| Connecteur de dashboard (Looker StudioâŠ) | Visualisation rapide | Aucun dĂ©veloppement | Pas dâhistorique propre, mĂȘmes limites que la source | Faible | En complĂ©ment dâun stockage |
Le schéma de table minimal
CREATE TABLE gsc_daily (
day DATE NOT NULL,
search_type VARCHAR(12) NOT NULL,
page VARCHAR(2048) NOT NULL,
query VARCHAR(512) NOT NULL,
country CHAR(3) NULL,
device VARCHAR(8) NULL,
clicks INT NOT NULL,
impressions INT NOT NULL,
ctr DECIMAL(7,6) NOT NULL,
position DECIMAL(7,2) NOT NULL,
collected_at DATETIME NOT NULL
);
Stockez les lignes brutes, puis calculez les vues dans le tableau de bord. Ne stockez pas un CTR ou une position « moyenne de moyennes » : recalculez-les à partir des clics, impressions et positions pondérées par les impressions.
Fréquence et rattrapage
- Quotidien : collectez la journée J-3 en
final. Relancez le mĂȘme jour quelques jours plus tard si vous utilisezall, car les donnĂ©es rĂ©centes peuvent Ă©voluer. - Rattrapage initial : bouclez jour par jour sur les seize mois disponibles, en espaçant les appels.
- Idempotence : une clĂ© unique (jour, type, page, requĂȘte, pays, appareil) Ă©vite les doublons en cas de relance.
Comparer des périodes sans se tromper
Comparez des pĂ©riodes de mĂȘme longueur et de mĂȘme composition hebdomadaire (28 jours contre les 28 prĂ©cĂ©dents, ou contre la mĂȘme pĂ©riode un an plus tĂŽt pour neutraliser la saisonnalitĂ©). Segmentez ensuite par rĂ©pertoire, appareil et pays : câest ce dĂ©coupage qui permet de distinguer un trafic en baisse malgrĂ© des positions stables dâune vraie perte de visibilitĂ©. Les mĂȘmes sĂ©ries servent Ă mesurer lâeffet dâune mise Ă jour dâancien article ou dâune migration de site.
De lâappel API quotidien au tableau de bord : collecter, stocker, comparer.
Une tĂąche planifiĂ©e interroge lâAPI, stocke les lignes puis alimente le rapport.
Les erreurs courantes et leur correction
| SymptĂŽme | Cause probable | Correction |
|---|---|---|
| 403 « insufficient permission » | Compte de service non ajoutĂ© Ă la propriĂ©tĂ©, ou mauvaise propriĂ©tĂ© | Ajouter lâadresse du compte dans Search Console ; vĂ©rifier sc-domain: ou prĂ©fixe exact avec la barre finale |
| 404 sur le site | siteUrl non encodĂ© ou diffĂ©rent de la propriĂ©tĂ© | Encoder lâidentifiant (sc-domain%3Aexemple.fr) |
| 400 sur les dates | Format invalide ou startDate postérieure à endDate | AAAA-MM-JJ, bornes incluses |
| 429 ou quota dĂ©passĂ© | Trop dâappels ou requĂȘtes trop lourdes | Espacer, rĂ©duire la pĂ©riode, retirer une dimension coĂ»teuse ; attendre 15 minutes |
| Réponse vide sur les derniers jours | Données pas encore finalisées | Utiliser J-3 ou dataState all |
| Totaux infĂ©rieurs Ă lâinterface | RequĂȘtes anonymisĂ©es, limite de lignes, agrĂ©gation | Comparer Ă une requĂȘte sans dimension query ; documenter lâĂ©cart |
Conclusion : un reporting fiable commence par une collecte modeste et réguliÚre
LâAPI Search Console ne rend pas le SEO plus visible : elle rend sa mesure plus complĂšte, plus ancienne et plus facile Ă croiser. Le bon point de dĂ©part tient en quatre dĂ©cisions : une propriĂ©tĂ© et un compte de service correctement autorisĂ©s, une requĂȘte quotidienne dâune journĂ©e, un stockage brut historisĂ© et des comparaisons calculĂ©es en aval.
Ces donnĂ©es alimentent ensuite le diagnostic : analyser une chute brutale de trafic SEO, suivre les positions par groupe de requĂȘtes ou relier les clics Google au trafic venant des assistants IA dans GA4. Si vous prĂ©fĂ©rez dĂ©lĂ©guer la chaĂźne de collecte, notre Ă©quipe dâautomatisation IA et data met en place des flux sĂ©curisĂ©s, et notre accompagnement SEO transforme ces sĂ©ries en prioritĂ©s. En cas de baisse dĂ©jĂ constatĂ©e, lâaudit de chute de trafic SEO part directement de ces exports.
FAQ : API Google Search Console
Non. LâAPI est gratuite ; elle est encadrĂ©e par des quotas documentĂ©s par Google (requĂȘtes par minute par site, par utilisateur et par projet, ainsi quâun quota de charge).
JusquâĂ 25 000 lignes par requĂȘte avec rowLimit, et davantage en paginant avec startRow. Google indique que la mĂ©thode Search Analytics expose au maximum 50 000 lignes par jour et par type de recherche, triĂ©es par clics.
Les lignes par requĂȘte excluent les requĂȘtes anonymisĂ©es, lâagrĂ©gation par page diffĂšre de lâagrĂ©gation par propriĂ©tĂ© et les limites de lignes coupent la longue traĂźne. Comparez des requĂȘtes construites de la mĂȘme façon.
Non : lâaccĂšs aux donnĂ©es dâune propriĂ©tĂ© exige une autorisation OAuth 2.0, via un compte utilisateur ou un compte de service ajoutĂ© Ă la propriĂ©tĂ©. Une simple clĂ© API ne suffit pas.
Non, lâAPI couvre la mĂȘme fenĂȘtre que lâinterface. Pour disposer dâun historique plus long, il faut stocker les donnĂ©es Ă mesure de leur collecte.
Une collecte quotidienne de la derniÚre journée disponible suffit dans la plupart des cas. Google recommande précisément de demander une journée à la fois.
Documentations officielles pour approfondir
Ces ressources sont proposĂ©es pour vĂ©rifier les procĂ©dures susceptibles dâĂ©voluer. Elles sont externes Ă Devsource et sâouvrent dans un nouvel onglet.
- Search Console API : méthode searchanalytics.query
- Search Console API : récupérer toutes ses données
- Search Console API : limites dâutilisation
- Search Console API : premiers pas et autorisation
- Google Search Central : filtrage et limites des données de performances
- Aide Search Console : rapport Performances
Du concept à une décision applicable
Ces ressources relient le diagnostic Ă une dĂ©finition, un outil de contrĂŽle et une preuve de mise en Ćuvre.








