Ce qui s'est passé sur le Merchant Center — et pourquoi vous devez réagir vite
Le 21 février 2026, le dashboard de statut de Google Merchant Center a affiché un incident actif sur le service "Feeds". Pas un simple avertissement : un flag de disruption affectant le traitement des flux produit. Concrètement, les feeds soumis pendant la fenêtre d'incident n'ont pas été processés normalement — ce qui signifie des fiches produit potentiellement désindexées de Google Shopping, des annonces Shopping désactivées faute de données produit à jour, et des campagnes Performance Max privées de leur carburant principal.
Ce type d'incident n'est pas rare. Google en a documenté plusieurs en 2024 et 2025 sur le même dashboard. Mais la majorité des marchands ne le découvrent que 48 à 72 heures plus tard, quand les impressions Shopping s'effondrent et que le ROAS plonge. Le temps de réaction fait toute la différence entre une perturbation de quelques heures et une perte de revenus sur plusieurs jours.
Cet article détaille l'anatomie technique de ce type de disruption, les mécanismes de détection que vous devriez avoir en place, et les contre-mesures concrètes pour minimiser l'impact.
Anatomie d'une disruption de feeds : ce qui casse et comment
Le pipeline de traitement des feeds Google
Pour comprendre ce qui dysfonctionne, il faut d'abord modéliser ce qui se passe quand Google traite un feed. Le pipeline simplifié ressemble à ceci :
- Fetch : Google récupère le fichier XML/TSV/CSV depuis votre URL de feed (ou via l'API Content for Shopping)
- Parse : le fichier est parsé, chaque item est extrait et validé contre le schéma de spécifications produit
- Validation : chaque champ est vérifié (GTIN valide, prix cohérent avec la landing page, disponibilité, images accessibles)
- Diffusion : les fiches validées sont propagées vers Google Shopping, les annonces Shopping, les surfaces gratuites (free listings) et Performance Max
Quand le dashboard signale une disruption sur "Feeds", cela peut toucher n'importe quelle étape. Mais historiquement, les incidents les plus fréquents concernent les étapes 1 (fetch échoué côté Google) et 4 (propagation bloquée). L'étape 2-3 est rarement en cause car elle est stateless — c'est du traitement pur sans dépendance à un état externe.
Scénario concret : e-commerce mode, 12 000 SKUs
Prenons un retailer mode avec 12 000 références actives, un feed principal soumis toutes les 6 heures, et un budget Shopping de 850€/jour réparti entre des campagnes Shopping standard et Performance Max.
Voici la chronologie type lors d'un incident comme celui du 21 février :
- T+0h : le feed de 14h est soumis normalement. Google le fetch, mais le processing est bloqué en file d'attente côté Merchant Center.
- T+6h : le feed de 20h est soumis. Même problème. Le feed de 14h n'a toujours pas été traité.
- T+8h : les fiches produit dont le prix ou la disponibilité a changé depuis le dernier feed réussi (celui de 8h) commencent à diverger. Google détecte des incohérences prix entre le feed et les landing pages lors de ses propres crawls de vérification.
- T+12h : Google désactive les fiches avec des incohérences détectées. Sur 12 000 SKUs, supposons que 15% ont eu un changement de prix ou de disponibilité dans la journée — 1 800 fiches sont suspendues.
- T+18h : les campagnes Shopping et PMax perdent 15% de leur inventaire éligible. Le CPC augmente sur les produits restants car la pression d'enchère se concentre sur moins de fiches. Le ROAS se dégrade.
- T+24h : si l'incident est résolu, Google reprocess les feeds en attente. Mais la réactivation des fiches suspendues prend encore 4 à 12 heures supplémentaires.
Bilan : entre 24 et 36 heures de performance dégradée. Sur un budget de 850€/jour avec un ROAS moyen de 5, c'est 850€ à 1 275€ de dépense publicitaire avec un rendement significativement inférieur — potentiellement 2 000€ à 4 000€ de chiffre d'affaires en moins.
Le piège des feeds supplémentaires
Beaucoup de marchands utilisent des feeds supplémentaires (supplemental feeds) pour enrichir les données : labels personnalisés, promotions, attributs spécifiques par marché. Ces feeds supplémentaires dépendent du feed principal pour le matching par id. Si le feed principal n'est pas processé, les supplémentaires sont orphelins — leurs données ne sont rattachées à rien.
C'est un point souvent négligé : la disruption d'un feed principal a un effet cascade sur tous les feeds supplémentaires qui en dépendent.
Monitoring proactif : détecter avant que les impressions ne chutent
Surveiller le statut du Merchant Center par API
Google expose l'état de traitement des feeds via l'API Content for Shopping v2.1. Vous pouvez interroger programmatiquement le statut de chaque feed pour détecter un blocage avant qu'il n'impacte vos campagnes.
Voici un script Node.js minimaliste qui interroge l'API et alerte en cas d'anomalie :
import { google } from 'googleapis';
const merchantId = '123456789';
const auth = new google.auth.GoogleAuth({
keyFile: './service-account-key.json',
scopes: ['https://www.googleapis.com/auth/content'],
});
async function checkFeedStatus(): Promise<void> {
const content = google.content({ version: 'v2.1', auth: await auth.getClient() });
const { data } = await content.datafeeds.list({ merchantId });
if (!data.resources) {
console.error('Aucun feed trouvé pour ce merchant ID');
return;
}
for (const feed of data.resources) {
const statusResp = await content.datafeedstatuses.get({
merchantId,
datafeedId: feed.id!,
});
const status = statusResp.data;
const lastProcessed = status.lastUploadDate;
const itemsValid = status.itemsValid ?? 0;
const itemsTotal = status.itemsTotal ?? 0;
const errorCount = status.errors?.length ?? 0;
// Détection d'anomalies
const validRatio = itemsTotal > 0 ? itemsValid / itemsTotal : 0;
const hoursSinceProcess = lastProcessed
? (Date.now() - new Date(lastProcessed).getTime()) / 3_600_000
: Infinity;
if (hoursSinceProcess > 8) {
alertSlack(`⚠ Feed "${feed.name}" non processé depuis ${hoursSinceProcess.toFixed(1)}h`);
}
if (validRatio < 0.85 && itemsTotal > 100) {
alertSlack(
`⚠ Feed "${feed.name}" : seulement ${(validRatio * 100).toFixed(1)}% items valides ` +
`(${itemsValid}/${itemsTotal}). ${errorCount} types d'erreurs.`
);
}
}
}
function alertSlack(message: string): void {
// Implémenter l'envoi webhook Slack/Teams/PagerDuty
console.warn(message);
}
// Exécuter toutes les 2 heures via cron
checkFeedStatus().catch(console.error);
Les deux seuils critiques ici :
- Délai de processing > 8h : si votre feed est soumis toutes les 6 heures et que le dernier traitement date de plus de 8 heures, quelque chose bloque.
- Ratio de validité < 85% : un drop soudain du ratio items valides / items totaux signale soit un problème dans votre feed, soit un bug de validation côté Google.
Corréler avec les métriques Shopping en temps réel
L'API Merchant Center ne vous dit pas tout. Vous devez aussi surveiller les métriques Shopping côté Google Ads pour détecter l'impact aval. Un script Google Ads peut faire ça :
function checkShoppingPerformanceDrop() {
const today = Utilities.formatDate(new Date(), 'UTC', 'yyyy-MM-dd');
const yesterday = Utilities.formatDate(
new Date(Date.now() - 86400000), 'UTC', 'yyyy-MM-dd'
);
const lastWeekSameDay = Utilities.formatDate(
new Date(Date.now() - 7 * 86400000), 'UTC', 'yyyy-MM-dd'
);
// Impressions aujourd'hui vs même jour semaine dernière
const queryToday = `
SELECT metrics.impressions, metrics.clicks, metrics.cost_micros
FROM shopping_performance_view
WHERE segments.date = '${today}'
`;
const queryLastWeek = `
SELECT metrics.impressions, metrics.clicks, metrics.cost_micros
FROM shopping_performance_view
WHERE segments.date = '${lastWeekSameDay}'
`;
const reportToday = AdsApp.search(queryToday);
const reportLastWeek = AdsApp.search(queryLastWeek);
let impressionsToday = 0;
let impressionsLastWeek = 0;
while (reportToday.hasNext()) {
impressionsToday += reportToday.next().metrics.impressions;
}
while (reportLastWeek.hasNext()) {
impressionsLastWeek += reportLastWeek.next().metrics.impressions;
}
if (impressionsLastWeek > 0) {
const dropPercent = ((impressionsLastWeek - impressionsToday) / impressionsLastWeek) * 100;
if (dropPercent > 30) {
MailApp.sendEmail(
'[email protected]',
`ALERTE : impressions Shopping en baisse de ${dropPercent.toFixed(1)}%`,
`Impressions aujourd'hui : ${impressionsToday}\n` +
`Impressions même jour semaine dernière : ${impressionsLastWeek}\n` +
`Vérifier immédiatement le statut des feeds Merchant Center.`
);
}
}
}
Le seuil de 30% en J/J-7 est calibré pour éviter les faux positifs liés aux variations normales de trafic. Ajustez-le à la volatilité de votre vertical — le fashion aura plus de variance que l'électronique grand public.
Contre-mesures immédiates pendant un incident Feeds
Vérifier la cohérence feed / landing pages
Pendant un incident de processing, le plus grand risque n'est pas que vos produits disparaissent temporairement — c'est que Google crawle vos pages produit et détecte des incohérences avec les dernières données de feed qu'il a en cache. Ces incohérences entraînent des suspensions qui persistent bien après la résolution de l'incident.
La parade : un script de vérification côté serveur qui compare votre feed actuel avec le contenu réel de vos pages. Voici une version simplifiée en Python :
import xml.etree.ElementTree as ET
import requests
from bs4 import BeautifulSoup
from concurrent.futures import ThreadPoolExecutor, as_completed
FEED_PATH = "./product_feed.xml"
NAMESPACE = {"g": "http://base.google.com/ns/1.0"}
MAX_WORKERS = 10
def parse_feed(feed_path: str) -> list[dict]:
tree = ET.parse(feed_path)
root = tree.getroot()
products = []
for item in root.findall(".//item"):
product = {
"id": item.findtext("g:id", namespaces=NAMESPACE),
"price": item.findtext("g:price", namespaces=NAMESPACE, default="").split()[0],
"availability": item.findtext("g:availability", namespaces=NAMESPACE),
"link": item.findtext("g:link", namespaces=NAMESPACE),
}
products.append(product)
return products
def check_landing_page(product: dict) -> dict | None:
"""Vérifie la cohérence prix/disponibilité entre le feed et la page."""
try:
resp = requests.get(product["link"], timeout=10, headers={
"User-Agent": "FeedChecker/1.0 (internal audit)"
})
if resp.status_code != 200:
return {"id": product["id"], "issue": f"HTTP {resp.status_code}", "url": product["link"]}
soup = BeautifulSoup(resp.text, "html.parser")
# Extraire le prix depuis les données structurées JSON-LD
import json
for script in soup.find_all("script", type="application/ld+json"):
try:
ld = json.loads(script.string)
if ld.get("@type") == "Product":
page_price = str(ld.get("offers", {}).get("price", ""))
page_availability = ld.get("offers", {}).get("availability", "")
issues = []
if page_price and page_price != product["price"]:
issues.append(f"Prix feed={product['price']} vs page={page_price}")
if "InStock" in (product.get("availability") or "") and "OutOfStock" in page_availability:
issues.append("Feed=in_stock mais page=OutOfStock")
if issues:
return {"id": product["id"], "issues": issues, "url": product["link"]}
except json.JSONDecodeError:
continue
except requests.RequestException as e:
return {"id": product["id"], "issue": f"Request failed: {e}", "url": product["link"]}
return None
def main():
products = parse_feed(FEED_PATH)
print(f"Vérification de {len(products)} produits...")
mismatches = []
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
futures = {executor.submit(check_landing_page, p): p for p in products}
for future in as_completed(futures):
result = future.result()
if result:
mismatches.append(result)
print(f"\n{len(mismatches)} incohérences détectées sur {len(products)} produits.")
for m in mismatches[:20]:
print(f" - {m['id']}: {m.get('issues', m.get('issue'))} | {m['url']}")
if __name__ == "__main__":
main()
Ce script compare les prix et la disponibilité entre votre feed XML et les données structurées JSON-LD de vos pages produit. En cas d'incident Merchant Center, exécutez-le immédiatement. Chaque incohérence détectée est un produit qui risque la suspension — corrigez le feed ou la page avant que Google ne le fasse pour vous.
Geler les modifications de prix pendant l'incident
C'est contre-intuitif mais efficace : si vous savez que vos feeds ne sont pas processés, évitez de modifier les prix ou la disponibilité sur votre site pendant la durée de l'incident. Chaque modification crée une divergence potentielle entre le cache Merchant Center et votre page.
Si vous avez un système de repricing automatisé, désactivez-le temporairement ou configurez-le pour ne pousser les changements qu'une fois l'incident résolu. Un flag dans votre système de configuration suffit :
# Dans votre crontab ou orchestrateur
# Désactiver le repricing pendant un incident MC
export MC_FEED_INCIDENT=true
# Dans votre script de repricing
if [ "$MC_FEED_INCIDENT" = "true" ]; then
echo "$(date): Repricing suspendu — incident Merchant Center actif" >> /var/log/repricing.log
exit 0
fi
Re-soumettre les feeds manuellement après résolution
Dès que le dashboard de statut repasse au vert, ne vous contentez pas d'attendre la prochaine soumission planifiée. Forcez une re-soumission immédiate via l'API :
# Via l'API Content for Shopping — forcer le fetch d'un feed
curl -X POST \
"https://shoppingcontent.googleapis.com/content/v2.1/${MERCHANT_ID}/datafeeds/${FEED_ID}/fetchNow" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json"
Faites-le pour chaque feed — principal et supplémentaires — dans l'ordre. Le feed principal d'abord, puis les supplémentaires 15 à 20 minutes après, pour laisser le temps au processing du principal.
Impact croisé : feeds, Shopping et Performance Max
Un point que peu d'articles couvrent : l'effet d'une disruption de feeds sur les campagnes Performance Max.
PMax consomme les données du Merchant Center comme signal d'entrée pour son optimisation algorithmique. Quand les feeds ne sont pas à jour, PMax ne se contente pas de réduire la diffusion Shopping — il redistribue le budget vers d'autres canaux (Display, YouTube, Search) où il n'a pas la même efficacité pour du e-commerce pur.
Concrètement, pendant un incident Feeds :
- Les assets Shopping de PMax sont dégradés ou désactivés
- L'algorithme de PMax redirige le budget vers Display et YouTube Discovery
- Le CPA augmente car ces canaux sont moins performants pour de la conversion directe
- Après résolution, PMax met 3 à 7 jours à réoptimiser sa répartition de budget
C'est pour ça qu'une disruption de 24h sur le Merchant Center peut affecter vos performances PMax pendant une semaine entière. La relation entre les placements PMax et la performance Shopping est directe — si le carburant (les fiches produit) manque, la machine redirige aveuglément.
Les données structurées comme filet de sécurité
Quand le feed Merchant Center est indisponible ou en retard de processing, Google continue de crawler vos pages produit. Si vos données structurées Product sont correctement implémentées, elles servent de source de vérité secondaire.
C'est ici que la qualité de votre markup JSON-LD fait la différence. Un markup minimal ne suffit pas — vous devez inclure tous les champs que Google utilise pour la validation croisée avec le feed :
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": "Veste en laine mérinos - Anthracite",
"sku": "VEST-MER-ANT-42",
"gtin13": "3760123456789",
"image": [
"https://cdn.votredomaine.com/products/vest-mer-ant-01.webp",
"https://cdn.votredomaine.com/products/vest-mer-ant-02.webp"
],
"brand": {
"@type": "Brand",
"name": "VotreBrand"
},
"offers": {
"@type": "Offer",
"url": "https://www.votredomaine.com/veste-laine-merinos-anthracite",
"priceCurrency": "EUR",
"price": "189.00",
"priceValidUntil": "2026-12-31",
"availability": "https://schema.org/InStock",
"itemCondition": "https://schema.org/NewCondition",
"shippingDetails": {
"@type": "OfferShippingDetails",
"shippingRate": {
"@type": "MonetaryAmount",
"value": "4.90",
"currency": "EUR"
},
"deliveryTime": {
"@type": "ShippingDeliveryTime",
"handlingTime": {
"@type": "QuantitativeValue",
"minValue": 0,
"maxValue": 1,
"unitCode": "DAY"
},
"transitTime": {
"@type": "QuantitativeValue",
"minValue": 2,
"maxValue": 4,
"unitCode": "DAY"
}
}
}
}
}
</script>
Le point crucial : le sku dans vos données structurées doit correspondre exactement à l'id dans votre feed Merchant Center. C'est ce champ qui permet à Google de faire le rapprochement entre la fiche crawlée et la fiche du feed. Si le matching échoue, Google traite les deux sources comme indépendantes et les incohérences deviennent des motifs de suspension.
Pour les sites qui utilisent du SSR ou du SSG, vérifiez que ce JSON-LD est bien présent dans le HTML initial servi au crawler, pas injecté côté client après hydratation. Un hydration mismatch sur les données structurées est particulièrement problématique car le prix visible par Google peut différer du prix réel. Si votre site est un SPA, le risque est encore plus élevé — Google pourrait voir une page blanche ou un état partiel de vos données produit.
Pour valider ce que Google voit réellement, testez le rendu côté crawler sur un échantillon de vos pages produit les plus stratégiques.
Construire un système de résilience long terme
Multi-source de feeds
Ne dépendez pas d'un seul mécanisme de soumission. Google Merchant Center supporte trois méthodes :
- Fetch planifié : Google récupère le fichier à une URL donnée selon un schedule
- Upload direct : vous poussez le fichier via SFTP ou l'interface
- API Content for Shopping : soumission produit par produit ou en batch via API
L'idéal est de combiner le fetch planifié (toutes les 6h) avec une soumission API pour les changements urgents (ruptures de stock, corrections de prix). Quand le fetch planifié est bloqué par un incident comme celui du 21 février, la soumission API peut potentiellement passer sur un pipeline de processing différent côté Google.
Monitoring multi-couche
La leçon principale de cet incident : le monitoring de vos feeds ne peut pas reposer uniquement sur l'interface Merchant Center. Vous devez surveiller la chaîne complète :
- Couche infrastructure : votre serveur de feed répond-il ? Le fichier XML est-il généré correctement ? (monitoring HTTP basique, validation XML schema)
- Couche Merchant Center : le feed est-il processé ? Combien d'items sont validés ? (API Content for Shopping, script TypeScript ci-dessus)
- Couche performance : les impressions Shopping sont-elles stables ? Le nombre de produits éligibles est-il constant ? (script Google Ads ci-dessus)
- Couche SEO : vos pages produit sont-elles toujours accessibles et cohérentes avec le feed ? (crawl régulier, vérification des données structurées)
Un outil de monitoring comme SEOGard gère la couche 4 en continu — détection de régressions sur les données structurées, surveillance de l'accessibilité des pages produit, alertes en cas de changement inattendu sur les meta ou le markup. C'est le filet de sécurité qui vous manque quand l'incident est côté Google et que vous ne contrôlez pas le pipeline de processing.
Documenter un runbook d'incident
Chaque équipe e-commerce devrait avoir un runbook "Incident Merchant Center" prêt à dérouler. Les points essentiels :
- Qui est alerté : le responsable acquisition + le responsable technique du feed
- Première action (T+0) : vérifier le dashboard de statut Google et l'API datafeedstatuses
- Si incident confirmé côté Google (T+0 à T+1h) : geler le repricing automatique, documenter l'heure de début
- Pendant l'incident : exécuter le script de cohérence feed/landing pages, corriger les divergences détectées
- Après résolution (T+Nh) : forcer le fetchNow sur tous les feeds, réactiver le repricing, monitorer les impressions Shopping pendant 7 jours
L'objectif n'est pas de prévenir l'incident — vous ne contrôlez pas l'infrastructure Google. L'objectif est de minimiser le blast radius et d'accélérer la récupération.
Ce qu'il faut retenir
Une disruption Feeds sur le Merchant Center n'est pas un événement exceptionnel — c'est un risque opérationnel récurrent qui doit être intégré dans votre stratégie de résilience e-commerce. La différence entre les marchands qui perdent quelques heures de performance et ceux qui perdent une semaine tient en trois éléments : un monitoring proactif multi-couche, des données structurées Product irréprochables comme source de vérité secondaire, et un runbook d'incident testé et prêt à dérouler. Mettez en place les scripts et les process décrits ici avant le prochain incident — parce qu'il arrivera.