Recherche interne e-commerce : métriques GA4 et actions prioritaires

Guide pratique pour instrumenter et analyser la recherche interne e‑commerce avec GA4 : événements à implémenter, métriques prioritaires et plan d’action sur PrestaShop.

Écran d'ordinateur affichant un tableau de bord analytique avec des graphiques et des données de performance.

Table des matières :

  1. Instrumenter la recherche interne pour GA4 (sans bruit, sans PII)
  2. Modèle GA4 : événements, paramètres et dimensions utiles à la recherche
  3. Métriques GA4 prioritaires pour une recherche interne e-commerce (et comment les calculer)
  4. De la métrique à l’action : plan de remédiation par ordre d’impact
  5. PrestaShop : limites du moteur natif et options (MySQL, facettes, Elasticsearch/Meilisearch)
  6. Mettre la recherche sous contrôle : BigQuery, alerting, tests et gouvernance

Instrumenter la recherche interne pour GA4 (sans bruit, sans PII)

Sur un site e-commerce, la recherche interne n’est exploitable que si l’instrumentation est cohérente (un événement = un résultat de recherche réellement affiché) et si la donnée est propre (pas de PII, pas de bots, pas de doublons). GA4 fournit un événement recommandé pour ça : view_search_results. La définition officielle est explicite :

« view_search_results : A user has performed a search on your site. » — Google Analytics, Recommended events (developers.google.com)

Sur PrestaShop (8.1+ / 8.2+ / 9.x, PHP 8.2/8.3), la page de résultats est typiquement index.php?controller=search&s=... (ou search_query= selon thème/modules). L’erreur classique est de déclencher l’événement au keyup dans l’autocomplete, ce qui gonfle artificiellement le volume de recherches et casse vos ratios (refinement, conversion, etc.). La règle : déclencher view_search_results uniquement quand la page de résultats est rendue (SSR ou client-side), et instrumenter séparément les suggestions (search_suggestion_click en custom event par exemple).

Pour garder une mesure « propre », vous pouvez vous caler sur cette checklist simple :

  • 1 recherche = 1 page (ou 1 rendu de liste) : pas d’événement sur le champ de saisie.
  • Déduplication : éviter de renvoyer 2 fois view_search_results (ex. SSR + JS qui re-tire l’événement).
  • Stabilité des paramètres : mêmes noms, même typage, mêmes règles de normalisation (et versionnage si vous changez de moteur).
  • Séparation autocomplete vs résultats : sinon vous mélangez « exploration » et « intention d’achat ».
  • Filtrage environnements : staging / préprod / QA tagués en traffic_type ou debug_mode (sinon vos tops termes deviennent inutilisables).

Côté conformité, GA4 interdit l’envoi de PII. La formulation de Google est sans ambiguïté :

« Do not send personally identifiable information to Google Analytics. » — Google Analytics Policies (support.google.com)

Concrètement : filtrez/normalisez le search_term (lowercase, trim, suppression diacritiques si besoin), et bloquez les patterns d’e-mails / téléphones / identifiants. Sur des boutiques B2B, les commerciaux tapent souvent des références internes, des e-mails, voire des numéros de commande : c’est exactement le genre de fuite à éviter.

Pour cadrer le volet « consentement » côté UE, le texte de référence reste le RGPD (acte positif clair, pas de consentement implicite) :

« Le consentement devrait être donné par un acte positif clair […] » — Règlement (UE) 2016/679 (RGPD), considérant 32 (EUR-Lex)

Implémentation minimale (gtag.js)

Si vous êtes en gtag.js (pas GTM), le plus robuste est de parser l’URL sur la page de résultats. Deux détails « terrain » utiles sur PrestaShop : (a) certains thèmes/modules utilisent search_query au lieu de s, (b) sur les catalogues multilingues, normaliser accents/casse réduit fortement la fragmentation des termes.

<script>
(function () {
  const url = new URL(window.location.href);
  const raw = (url.searchParams.get('s') || url.searchParams.get('search_query') || '').trim();

  // Normalisation simple (à adapter : langues, règles métier)
  const term = raw
    .normalize('NFD').replace(/[\u0300-\u036f]/g, '')   // retire diacritiques
    .replace(/\s+/g, ' ')                               // espaces multiples
    .slice(0, 150);                                     // évite les chaînes aberrantes

  // Anti-PII basique (à durcir selon contexte)
  const looksLikeEmail = /@/.test(term);
  const looksLikePhone = /\b\+?\d[\d\s().-]{7,}\b/.test(term);

  if (!term || looksLikeEmail || looksLikePhone) return;

  // Optionnel: compter le nombre de résultats côté DOM (selon thème)
  const resultsCount = document.querySelectorAll('.product-list .product-miniature').length;

  gtag('event', 'view_search_results', {
    search_term: term.toLowerCase(),
    search_results_count: resultsCount,
    search_has_results: resultsCount > 0
  });
})();
</script>

Deux points importants : (1) search_results_count et search_has_results sont des paramètres custom : vous devrez les déclarer comme dimensions personnalisées dans GA4 si vous voulez les exploiter sans BigQuery. (2) le sélecteur CSS dépend fortement du thème (classic vs Hummingbird vs custom). Si vous avez un thème moderne, gardez vos sélecteurs stables (data-attributes) plutôt que des classes décoratives ; cf. approche perf/front dans vos chantiers thème.

Enfin, testez systématiquement dans DebugView (GA4) et en conditions réelles : navigation via facettes, tri, pagination, retour arrière du navigateur. Sur les thèmes qui chargent la liste en AJAX (ou en SPA), l’événement doit être déclenché au moment où la liste est effectivement mise à jour, pas au clic sur « Filtrer ».

Modèle GA4 : événements, paramètres et dimensions utiles à la recherche

GA4 repose sur un modèle événementiel : pour analyser un parcours « recherche → clic → panier → achat », vous devez relier des événements entre eux (souvent via la session et le contexte de liste). La page d’aide About events rappelle la logique « interactions = events » et la centralité des événements dans GA4 (support.google.com).

Pour la recherche interne e-commerce, le trio minimum est :

  • view_search_results (terme + contexte de résultats)
  • select_item (clic sur un produit depuis une liste de résultats)
  • add_to_cart / purchase (pour relier recherche → revenu)

Dans GA4, search_term est un paramètre standard de view_search_results. En revanche, GA4 ne connaît pas nativement : la position du clic, le nombre de résultats, le fait que l’utilisateur clique une suggestion plutôt qu’un résultat, ou qu’il refine sa requête. Ce sont des signaux UX critiques : sans eux, vous pilotez à l’aveugle.

Le pattern qui marche en prod consiste à enrichir avec des paramètres custom stables et versionnés :

  • search_results_count (integer)
  • search_has_results (boolean)
  • search_page (integer) si pagination
  • search_sort (string) si tri (pertinence/prix)
  • search_filters (string ou JSON sérialisé) si facettes
  • search_click_position (integer) sur select_item
  • search_backend (mysql, ps_searchbar, elasticsearch, meilisearch, etc.) pour comparer les moteurs après migration

Sur PrestaShop, vous pouvez pousser ces infos via dataLayer (GTM) ou via JS natif du thème. Si vous utilisez ps_facetedsearch, considérez l’événement de filtrage comme un view_item_list ou un custom event type search_refine : GA4 ne vous donnera pas une « refinement rate » gratuitement. Et si vous migrez vers un moteur externe (Elastic/Meili/OpenSearch), gardez le même schéma d’événements pour pouvoir comparer avant/après.

Un schéma minimal (et lisible) pour relier correctement clics et résultats ressemble à ça :

Moment Événement GA4 Paramètres clés Pourquoi c’est utile
Résultats affichés view_search_results search_term, search_results_count, search_backend Qualité (0 résultat), comparaison moteurs
Impression liste (optionnel mais puissant) view_item_list item_list_name='search_results', items CTR fiable et analyse positionnelle
Clic produit select_item item_list_name, search_click_position Mesurer pertinence/ranking
Ajout panier / achat add_to_cart / purchase items, value, currency Impact business (revenu)

Pour les boutiques à forte volumétrie, le vrai terrain de jeu, c’est BigQuery Export : vous récupérez les événements bruts (et pas juste des rapports). Google documente le mécanisme ici : BigQuery Export pour GA4. C’est aussi le seul moyen propre de faire des métriques composées (ex. « sessions avec recherche et achat dans les 24h ») sans vous battre avec les limites d’Explorations.

Métriques GA4 prioritaires pour une recherche interne e-commerce (et comment les calculer)

La recherche interne e-commerce se pilote avec des métriques qui combinent usage, qualité de résultats, impact business. Les vanity metrics (volume brut de recherches) ne servent à rien si vous n’avez pas (a) la part de sessions concernées, (b) la part qui aboutit à un clic produit, (c) la part qui convertit.

Avant de rentrer dans le détail, gardez une lecture « orientée action » :

Métrique Si ça se dégrade… Actions probables (ordre typique)
Search Usage Rate Searchbox cachée ou navigation insuffisante UX header, accès mobile, catégories, filtres
Zero-Results Rate Index cassé, synonymes manquants, catalog incomplet Synonymes, accents, enrichissement produit, règles
Search CTR Pertinence faible ou perf page médiocre Ranking/boost, stock, perfs LCP/INP, facettes
Refinement/Pogo-sticking Résultats non satisfaisants Pertinence, filtres, suggestions, performance
Conv. searchers vs non-searchers Recherche aide ou fait perdre Fixes « top queries », tests A/B backend

1) Taux d’usage de la recherche (Search Usage Rate)

Définition : sessions (ou utilisateurs) ayant au moins un view_search_results / sessions (ou utilisateurs) totales. À utiliser en segmentation (mobile vs desktop, nouveaux vs récurrents). Un taux très bas peut indiquer une searchbox peu visible ; un taux très haut peut indiquer une navigation/catégorisation déficiente (et donc une dépendance à la recherche).

En BigQuery (pseudo-SQL simplifié), l’idée est d’agréger par ga_session_id :

WITH sessions AS (
  SELECT
    user_pseudo_id,
    (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS session_id,
    MAX(IF(event_name = 'view_search_results', 1, 0)) AS has_search
  FROM `project.analytics_XXXX.events_*`
  WHERE _TABLE_SUFFIX BETWEEN '20260901' AND '20260907'
  GROUP BY 1,2
)
SELECT
  SAFE_DIVIDE(SUM(has_search), COUNT(*)) AS search_usage_rate
FROM sessions;

Point de vigilance : sur certains setups, une même session peut contenir plusieurs termes (refinement). Ici, on mesure juste « au moins une recherche ». Pour une analyse plus fine, vous regarderez aussi le nombre médian de recherches par session (souvent plus stable que la moyenne, très sensible aux bots).

2) Taux de zéro résultat (Zero-Results Rate)

Sans search_results_count, vous ne pouvez pas le calculer correctement. C’est précisément le problème des implémentations « GA4 par défaut » : elles trackent des termes mais pas la qualité. Dès que vous avez search_has_results, vous sortez la métrique en une ligne.

WITH searches AS (
  SELECT
    user_pseudo_id,
    (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS session_id,
    (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'search_term') AS term,
    (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'search_results_count') AS cnt
  FROM `project.analytics_XXXX.events_*`
  WHERE event_name = 'view_search_results'
)
SELECT
  SAFE_DIVIDE(COUNTIF(cnt = 0), COUNT(*)) AS zero_results_rate,
  APPROX_TOP_COUNT(term, 20) AS top_terms
FROM searches;

À prioriser : les termes fréquents à 0 résultat (perte directe), puis les termes rares mais « à forte intention » (ex. “référence SKU exacte”). Dans PrestaShop, le 0 résultat provient souvent de : stemming inexistant, synonymes non gérés, accentuation/casse, et indexation produit incomplète (mots-clés non remplis).

Astuce opérationnelle : segmentez le 0 résultat par device et par langue (si multilingue). En pratique, les fautes de frappe et requêtes « télégraphiques » (sans accents, sans articles) explosent sur mobile, et ça change vos priorités de synonymes/corrections.

3) Taux de clic après recherche (Search Click-Through)

Définition : recherches qui mènent à un clic produit (select_item dans un item list de type « search results ») / recherches totales. Vous devez distinguer les clics issus de la recherche vs des catégories. Le plus fiable est de taguer item_list_name = 'search_results' sur l’impression de liste, puis sur le select_item.

Un CTR bas alors que results_count est élevé = pertinence/ranking pourri. Un CTR bas avec results_count faible = indexation insuffisante, trop de filtres, ou requêtes trop spécifiques.

  • results_count stable,
  • CTR qui baisse,
  • pogo-sticking qui monte,
  • et, côté business, un écart « searchers vs non-searchers » qui se resserre (la recherche n’aide plus).

Sans instrumentation de stock (au moins via règles de ranking), vous risquez de « corriger » le problème au mauvais endroit (synonymes, UI…).

4) “Refinement rate” et “Search pogo-sticking”

Refinement rate : sessions où l’utilisateur fait ≥2 view_search_results dans la même session. Le pogo-sticking est plus agressif : recherche → clic produit → retour résultat → autre clic. Ce sont des signaux de résultats non satisfaisants.

En GA4, vous ne l’obtenez pas proprement en rapport standard ; en BigQuery, c’est une analyse de séquences d’événements par session. C’est typiquement ce qui permet de justifier une migration vers Elastic/Meili/OpenSearch, plutôt que d’optimiser à la marge.

  • la part de recherches sans select_item dans les X secondes/minutes,
  • et la part de sessions « recherche + ≥2 pages produits vues » (souvent corrélée à l’insatisfaction, selon votre catalogue).

5) Conversion des “searchers” vs “non-searchers”

Le KPI business : taux de purchase et revenu par session pour les sessions avec recherche vs sans recherche. Si vos searchers convertissent moins, la recherche dégrade l’expérience (ou attire des utilisateurs perdus). Si vos searchers convertissent beaucoup plus, la recherche est un levier direct à fiabiliser (et à accélérer). C’est aussi un bon test pour valider une refonte du moteur.

Conseil de lecture : comparez aussi la valeur moyenne du panier et le taux d’ajout au panier après recherche. Sur certains catalogues, la recherche sert surtout à trouver la bonne référence (fort taux d’ajout, panier moyen stable), sur d’autres elle sert à explorer (plus de pages vues, panier moyen parfois plus haut).

De la métrique à l’action : plan de remédiation par ordre d’impact

Une fois les métriques disponibles, l’erreur est de partir en « tuning de pertinence » sans traiter les causes triviales. Sur PrestaShop, le cœur ne vous donne ni gestion fine des synonymes, ni scoring transparent, ni logs de requêtes utilisateur exploitables. Donc on priorise ce qui fait bouger les courbes rapidement et avec peu de risque.

Priorité 1 — Nettoyer la donnée : bots, doublons, PII, termes “bruit”

Si votre recherche interne est indexée par des robots (ou martelée par des monitors), vous allez voir des termes incohérents, des volumes anormaux et des taux de zéro résultat absurdes. Filtrez au niveau WAF/CDN (règles Cloudflare, rate limiting) et au niveau GA4 (traffic_type pour IP internes, environnements de staging). Les quotas et 429 côté API sont un sujet adjacent si vous instrumentez via server-side ; cf. API Rate Limits : comprendre les quotas, headers de limite et erreurs 429.

Sur le search_term, normalisez et dédoublonnez (ex. “iphone-15”, “iphone 15”, “Iphone15”). Une normalisation simple peut réduire de 10–30% le nombre de termes uniques dans des catalogues larges, ce qui rend vos « top 50 requêtes » enfin actionnables. Et oui, c’est du travail d’ingénierie data, pas un réglage GA4.

Enfin, bloquez/masquez les PII. Ne cherchez pas à “hasher pour être safe” : si vous envoyez un identifiant personnel même hashé, vous vous exposez quand même à des problèmes de conformité (ré-identification possible). La bonne stratégie est : détecter → ne pas envoyer.

Priorité 2 — Traiter les “top zero-results” avec des correctifs deterministes

Les top termes à zéro résultat, c’est de l’argent laissé sur la table. Actions « rapides » :

  • ajouter des synonymes (ex. “tee shirt” ↔ “t-shirt”),
  • gérer les accents (café vs cafe),
  • créer des redirections vers catégories/landing pages quand la recherche est en réalité une navigation (ex. “livraison”, “retour”),
  • enrichir le contenu produit (mots-clés, attributs) et les index.

Le lien SEO est immédiat : une recherche interne qui renvoie 0 résultat ressemble à une « page vide » côté UX, donc abandon. Les méthodes d’audit de contenu manquant et de pages pauvres restent utiles : Audit SEO HTML : diagnostiquer balises H1 H2 et contenu manquant.

Exemple terrain (boutique ~50k SKU) : en 2 semaines, correction des 30 requêtes à 0 résultat les plus fréquentes (synonymes + enrichissement attributs) → zéro-results rate passé de ~18% à ~7%, et +4% de revenu sur les sessions “searchers”. Ce genre de gain arrive avant toute migration technique, à condition d’avoir results_count tracké.

Priorité 3 — Corriger la pertinence (ranking) avec des signaux mesurables

Si results_count est élevé mais CTR bas, c’est du ranking. Là, vous devez ajouter des signaux : position de clic (search_click_position), et idéalement « clic sur suggestion vs clic sur résultat ». Sans position, vous ne sais pas si l’utilisateur clique systématiquement en bas de page (mauvaise pertinence en tête) ou s’il ne clique jamais.

Côté actions, commencez par du déterministe : boost des produits en stock, pénalisation des produits hors stock, boost des marques/catégories correspondant au terme, gestion des requêtes “marque + modèle”. Beaucoup de modules “recherche intelligente” font ça sans transparence : vous voulez des règles versionnées, testées, et comparables avant/après.

Un bon garde-fou : créez une petite liste de requêtes « critiques » (ex. top 20 + 20 requêtes SAV + 20 références exactes) et testez-la à chaque évolution de règles. C’est la version « test de non-régression » côté search.

Priorité 4 — Performance de la page de résultats (LCP/INP) et charge backend

La recherche interne est souvent une page lourde : facettes, pagination, appels AJAX, templates. Sur mobile, un LCP dégradé suffit à réduire mécaniquement le CTR et à gonfler le pogo-sticking. Le rappel Web Vitals est clair :

« Largest Contentful Paint (LCP) should occur within 2.5 seconds of when the page first starts loading. » — web.dev, Core Web Vitals (web.dev/vitals)

Pour PrestaShop, traitez ça comme un chantier perf classique : profiling PHP, requêtes SQL, cache, et rendu front. Pour une méthode reproductible et des preuves (TTFB, slow queries, waterfall), voir Audit performance PrestaShop : méthode reproductible et preuves terrain et Index MySQL : composer, mesurer avec EXPLAIN et optimiser les requêtes.

PrestaShop : limites du moteur natif et options (MySQL, facettes, Elasticsearch/Meilisearch)

Le moteur de recherche natif PrestaShop (et sa stack historique) a des limites structurelles : scoring peu maîtrisable, gestion des synonymes limitée selon modules, analyse linguistique faible, et performances qui se dégradent vite avec le volume (catalogues > 20–50k produits, multilingue, attributs complexes). Le résultat typique : beaucoup de « résultats pas vraiment pertinents » et une dette technique qui finit en migration forcée.

En français, les irritants sont souvent très concrets : pluriels/singuliers, accents, tirets (t-shirt), élisions (l’, d’), et requêtes « marque + modèle » saisies sans espaces. Si vous restez sur un moteur minimaliste, vous compenserez via :

  • un dictionnaire de synonymes,
  • des règles « exact match SKU d’abord »,
  • et une indexation produit/attributs plus riche (noms d’attributs, compatibilités, usages).

Si vous restez sur MySQL/MariaDB, vous devez accepter des compromis : LIKE/fulltext, indexation à surveiller, et tuning SQL/serveur. Dans les environnements chargés, vous finissez par devoir optimiser cache + base (Redis/OPcache, query cache applicatif) ; cf. Cache PrestaShop : stratégie 2026 OPcache, Redis, Varnish et CDN. Ça améliore le temps de réponse, pas la pertinence.

La facette (ps_facetedsearch) améliore la navigabilité, mais elle ne remplace pas une recherche robuste : la plupart des problèmes “zéro résultat” viennent de la requête utilisateur, pas des filtres. Et attention sécurité : le module a déjà eu des vulnérabilités sérieuses, donc patching strict et audits réguliers (voir l’analyse RCE : Vulnérabilité PrestaShop ps_facetedsearch : analyse RCE via unserialize()). Techniquement, surveillez aussi l’explosion de combinaisons de filtres et le coût des requêtes.

Quand vous basculez sur un moteur dédié, vous achetez surtout : analyse de texte, scoring explicable, synonymes/stopwords, tolérance aux fautes, et latence stable. Deux options documentées sur ce site :

Le point non négociable côté analytics : taguez search_backend dans GA4 avant et après migration, sinon vous ne saurez pas attribuer l’amélioration (ou la régression) à la techno. Et si vous exposez des endpoints de recherche (autocomplete, API), protégez-les : rate limiting, cache, signatures si webhook, etc.

Mettre la recherche sous contrôle : BigQuery, alerting, tests et gouvernance

Une fois l’instrumentation posée, l’objectif est d’industrialiser : dashboards, alerting et boucles de tests. GA4 Explorations suffit pour du ponctuel, mais pas pour du pilotage continu (changements de définition, limites d’échantillonnage/thresholding selon cas, difficulté à faire des métriques séquentielles). En pratique : export BigQuery quotidien, table de métriques dérivées (dbt ou SQL scheduled), et un tableau de bord (Looker Studio ou Grafana selon stack).

Sur l’alerting, trois alarmes donnent un ROI immédiat :

  1. Spike de zero-results rate (souvent lié à une régression de synonymes, une mise à jour de catalogue, ou un bug d’indexation).
  2. Chute du search CTR (pertinence/ranking cassé, produits hors stock remontés, ou performance dégradée).
  3. Hausse de latence sur l’endpoint de recherche / page résultats (corrélée à erreurs 503/500).

Pour que l’alerte soit actionnable, rattachez-la à une « hypothèse » et à un propriétaire. Exemple simple :

  • Seuil : +30% de zero-results rate vs moyenne J-14,
  • Diagnostic express : top 20 termes concernés + part par device + changement récent (synonymes, import produits),
  • Action : rollback règles / réindexation / correctif contenu.

Si vous voyez des 503/500 pendant les pics de recherche (campagnes, soldes), traitez la cause infra/app avant de retoucher la pertinence ; cf. Erreur HTTP 503 : diagnostiquer PHP et logs Apache/LiteSpeed et Erreur 500 PrestaShop : 10 causes fréquentes et solutions rapides.

Enfin, mettez en place une boucle d’expérimentation propre : A/B test sur règles de ranking (ou sur un nouveau backend), validation par segments (mobile, nouveaux, SEO vs SEA), et critères de succès explicites : baisse zero-results, hausse CTR, hausse conversion “searchers”, baisse pogo-sticking. Sans ça, vous « améliorez » la recherche au feeling et vous cassez des cas d’usage réels (SKU exacts, marques, compatibilités).

Pour garder la stabilité, versionnez vos règles (synonymes, boosts) comme du code, et déployez-les avec vos pipelines (mêmes exigences que vos modules : tests, rollback, staging). Une recherche interne e-commerce performante, ce n’est pas un « module magique » : c’est un produit à part entière, mesuré, gouverné et amélioré en continu.


À lire aussi