Tout projet d’analytics e-commerce arrive au même moment. Quelqu’un ouvre trois onglets (GA4, l’export des commandes SFCC et le fichier hors ligne) et dit : « Ces chiffres ne collent pas. Lequel est le bon ? »

La réponse qui met fin à la confusion ouvre aussi des questions bien plus intéressantes : les trois sont justes, et les écarts entre eux ne sont pas des erreurs à corriger, ce sont des informations à extraire.

Cet article est le deuxième d’une série sur la réconciliation GA4 / SFCC / hors ligne dans Looker. Avant tout pipeline ou modèle LookML, il faut comprendre pourquoi ces sources divergent : c’est un problème conceptuel, pas technique.

Trois systèmes, trois réalités

GA4, SFCC et vos sources hors ligne ne mesurent pas le même événement. Ils n’observent pas au même endroit, ne capturent pas de la même façon et ne définissent pas une transaction de la même manière.

Three Systems, Three Observation Points GA4 Browser-side event capture ✔ Web purchases (cookie present) ✔ Session attribution paths ✔ Funnel & behaviour data ✗ Offline orders ✗ Safari ITP losses (7-day) ✗ Refunds (unless implemented) ✗ WebView / in-app orders ✗ B2B / back-office orders Fires at browser purchase event SFCC Order management system ✔ All web orders confirmed ✔ Back-office / agent orders ✔ Order lifecycle (cancel/refund) ✔ Gross + net revenue ✔ Shipping, taxes, discounts ✗ Attribution / channel source ✗ Session behaviour data ✗ Marketing touchpoints Records at order confirmation OFFLINE / ERP POS, call centre, wholesale ✔ In-store POS transactions ✔ Phone / call centre orders ✔ Wholesale / B2B orders ✔ ERP-imported transactions ✗ No GA4 session ever ✗ No digital attribution ✗ No browser touchpoints Syncs to SFCC or BigQuery Green = captures · Red = blind spot · Reconciliation joins all three in BigQuery
Figure 1 : chaque système a sa propre fenêtre d’observation. Les écarts entre eux sont structurels, pas accidentels. Réconcilier, c’est comprendre ce que contient chaque colonne, pas les forcer à s’accorder.

GA4 : ce que le navigateur a bien voulu vous dire

GA4 est un système de collecte d’événements côté client. Toute sa vision de votre activité dépend du code JavaScript qui se déclenche dans le navigateur, de ce que ce navigateur autorise à envoyer, et d’un cookie persistant qui relie l’événement à une session précédente. Chacune de ces conditions peut échouer en silence.

Ce que GA4 capture bien : le comportement en session (pages vues, scroll, clics, ajouts au panier, étapes du checkout), les chemins d’attribution (canal, campagne, source), les achats (revenu, articles, transaction ID, quand l’événement purchase se déclenche correctement) et les signaux d’identité (client ID, user ID si implémenté, GCLID).

Ce que GA4 rate par construction :

Le revenu GA4 est donc : la somme des valeurs des événements purchase arrivés jusqu’au point de collecte de Google depuis une session navigateur où un cookie était présent et le tracking autorisé, à l’instant où l’événement s’est déclenché. Une définition très précise, et très bornée.

SFCC : la source de vérité comptable

Salesforce Commerce Cloud est la plateforme e-commerce où naissent les commandes web ; c’est le système de référence pour ces commandes (souvent aux côtés d’un OMS/ERP). Son rôle : enregistrer chaque transaction commerciale, suivre son cycle de vie et alimenter la logistique, la finance et le service client. Peu lui importe comment le client est arrivé. Ce qui compte : une commande a été passée, confirmée, puis livrée ou annulée.

Simplified business lifecycle (illustrative):

created → payment_pending → payment_confirmed → exported (to WMS)
                                      ↓
                              shipped → delivered
                                      ↓
                              return_requested → return_received → refunded

Alternative paths:
created → payment_failed → (abandoned)
created → fraud_review → cancelled

Dans SFCC, une commande porte des statuts séparés : commande (CREATED, NEW, OPEN, COMPLETED, CANCELLED, FAILED), paiement (NOTPAID, PARTPAID, PAID), export (NOTEXPORTED, READY, EXPORTED, FAILED) et expédition. Les retours et remboursements vivent le plus souvent dans l’OMS/ERP.

GA4 déclenche purchase à l’étape « paiement confirmé » de ce cycle simplifié, plus précisément au chargement de la page de confirmation. Mais l’enregistrement SFCC persiste pendant tout le cycle. Comparer le « revenu » GA4 (un instantané à la confirmation) au revenu net SFCC (qui intègre tous les événements ultérieurs) crée donc un écart structurel qui n’est pas un bug.

Ce que SFCC sait et que GA4 ignore : le statut final de la commande, le montant facturé exact (taxes, remises serveur, points de fidélité), le système qui a créé la commande, toutes les commandes quel que soit le canal, et l’identité au niveau du compte.

Ce que SFCC ignore : presque tout du marketing. Il peut stocker un source code (si vos campagnes en utilisent) et un type de canal (boutique, centre d’appels, marketplace…), mais pas le parcours au niveau du clic : clic Google Ads, recherche organique, e-mail. Cette couche d’attribution vit dans GA4 et les plateformes publicitaires. Il faut donc les deux systèmes dans votre modèle de réconciliation, aucun ne suffit seul.

Les cinq causes structurelles d’écart

1. Décalage temporel

GA4 se déclenche au chargement de la page de confirmation. SFCC enregistre la commande quand le paiement est confirmé côté back-end, après validation de la passerelle de paiement, contrôle antifraude et réservation du stock. Le délai se compte en général en secondes, mais peut atteindre des heures, voire des jours (revue manuelle antifraude, rappel tardif du prestataire de paiement). Sur une fenêtre de reporting en milieu de mois, c’est négligeable. Aux frontières de période, c’est un vrai écart :

Illustrative example:
User completes checkout at 23:59:57 on December 31st
  → GA4 fires purchase event: December (revenue lands in Dec)
  → Payment gateway confirms at 00:00:04 January 1st
  → SFCC records order: January (revenue lands in Jan)
Result: This order appears in GA4 December report but not SFCC December report.

Vérifiez aussi les fuseaux horaires : l’event_date de GA4 suit le fuseau de la propriété (alors que event_timestamp est en UTC), et les exports SFCC sont souvent en UTC. Cela suffit à déplacer des commandes d’un jour ou d’un mois à l’autre.

Diagnostic : comparez les commandes par jour entre GA4 et SFCC sur 30 jours. Un décalage glissant de 1 à 2 jours signale un problème de timing, qui se résorbe à l’agrégation mensuelle.

2. Définitions du revenu différentes

C’est la cause la plus souvent sous-diagnostiquée. GA4 reçoit la valeur que pousse votre dataLayer. SFCC enregistre sa propre définition financière de la valeur de commande. Sans alignement explicite, elles divergent sur chaque commande concernée :

ComposanteComportement GA4 typiqueComportement SFCC typiqueImpact si non aligné
Frais de livraisonSpec GA4 : exclus de value (envoyés dans shipping)Inclus dans totalGrossPriceComparer value à adjustedMerchandizeTotalPrice, pas au total de commande
TVA / taxesSpec GA4 : exclues de value (envoyées dans tax)SFCC stocke brut et netS’aligner sur la valeur nette des marchandises
Remises promotionnellesSouvent la valeur avant remise dans le dataLayerLe montant après remise est l’order_valueGA4 surestime le revenu de chaque commande remisée
Points de fidélitéRarement déduitsRéduisent le montant facturéGA4 surestime pour les clients du programme
DeviseDépend du paramètre de devise du dataLayerStockée en devise d’origine + convertieÉcarts de change systématiques sur les sites multi-devises

Correctif : avant tout travail technique, décidez ce que « revenu » veut dire : brut ou net ? Avec ou sans livraison ? Avec ou sans TVA ? Puis auditez votre dataLayer face à adjustedMerchandizeTotalPrice sur un échantillon de 50 commandes. La spec purchase de GA4 dit « Don’t include shipping or tax » dans value, et SFCC expose ces montants dans des totaux séparés. Si les valeurs diffèrent d’un pourcentage fixe, vous avez un problème de définition à corriger à la source.

3. Commandes annulées et remboursées

GA4 enregistre le revenu quand purchase se déclenche. SFCC suit la commande sur tout son cycle. Si un client demande un remboursement deux semaines plus tard, SFCC ajuste le revenu net ; GA4 non, sauf si vous envoyez explicitement un événement refund. Il faut pour cela un déclencheur côté serveur (Measurement Protocol) ou un tag GTM activé quand votre OMS traite le remboursement. La plupart des implémentations n’en ont pas : GA4 surestime alors durablement le revenu des catégories à fort taux de retour. Pour chiffrer cet écart dans BigQuery :

-- Quantify the refund gap in BigQuery
SELECT
  DATE_TRUNC(created_at, MONTH)         AS month,
  SUM(order_value)                       AS sfcc_gross_revenue,
  SUM(order_value - COALESCE(refund_amount, 0)) AS sfcc_net_revenue,
  SUM(COALESCE(refund_amount, 0))        AS total_refunds,
  ROUND(
    SUM(COALESCE(refund_amount, 0))
    / NULLIF(SUM(order_value), 0) * 100, 1
  )                                      AS refund_rate_pct
FROM `project.sfcc.orders`
WHERE status NOT IN ('cancelled', 'fraud', 'test')
  AND DATE(created_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 6 MONTH)
GROUP BY 1
ORDER BY 1
-- Compare refund_rate_pct with the GA4–SFCC revenue gap: if they are close,
-- missing refund events explain most of it.

4. Perte de cookies : ITP et Consent Mode

L’Intelligent Tracking Prevention (ITP) de Safari supprime les cookies posés par JavaScript après 7 jours sans visite, ou après 24 heures quand le visiteur arrive par un lien décoré venant d’un site classé comme tracker. Sans consentement (mode basique), l’achat n’atteint jamais GA4. Avec l’ITP, l’achat atteint GA4 mais souvent comme nouveau visiteur : la source d’acquisition d’origine est perdue.

Si votre cycle de réflexion moyen est inférieur à 7 jours, l’impact est minime. Pour des produits étudiés 1 à 4 semaines (voyage, électronique, luxe), c’est un problème d’attribution structurel et permanent. Regardez la part de Safari dans votre GA4 (Technologie > Navigateur).

5. Commandes passées hors navigateur

Une part importante et croissante des commandes est passée dans des environnements où les tags GA4 ne se déclenchent pas, ou mal :

L’architecture complète du flux de données

Data Flow: From Source Systems to Reconciliation Layer Browser / GTM GA4 Collection(events + sessions) GA4 → BigQuery Export(daily, event-level) SFCC Storefront(web + back-office) SFCC Order DB(full lifecycle) SFCC → BigQuery(API or nightly export) POS / Call CentreERP / Wholesale SFCC sync / CSV(or ERP direct) Offline → BigQuery(CSV upload or pipeline) BigQuery Unified warehouse All sources joined Looker LookML model + dashboards Normalisation happens before Looker (in BigQuery views): LOWER(TRIM(transaction_id)) = LOWER(TRIM(order_id)) · Revenue definition aligned · Status filters applied
Figure 2 : flux de données des systèmes sources vers la couche de réconciliation. Le principe : tout poser d’abord dans BigQuery, normaliser dans BigQuery, puis laisser Looker gérer la modélisation et la présentation.

Ce que l’écart vous dit vraiment

Une fois les causes structurelles comprises, l’écart cesse d’être un problème à résoudre et devient un instrument de mesure.

Quatre décisions métier avant tout travail technique

Avant d’écrire une requête SQL, répondez à ces quatre questions. Ce sont des décisions métier, pas techniques.

  1. Qu’est-ce que le revenu ? Valeur brute confirmée (livraison et TVA incluses, avant remboursements), montant net facturé (hors TVA, hors livraison, après remises) ou net encaissé (après remboursements et rétrofacturations) ? Il n’y a pas de réponse universelle : la finance veut le net encaissé, le marketing le brut facturé. Le dashboard doit exposer les trois, avec la définition affichée sur chaque métrique.
  2. Quelle est la clé de jointure ? Le transaction_id de GA4 correspond-il à l’order_id de SFCC ? Toujours ? Après normalisation ? Jamais ? Le prochain article de la série le traite en détail : c’est le point de défaillance le plus fréquent de tout projet de réconciliation.
  3. Quelles commandes sont dans le périmètre ? Web seul ? Tous canaux ? Avec ou sans B2B, avec ou sans annulées ? Le périmètre fixe le dénominateur de chaque indicateur d’écart : 20 % d’écart sur le web seul ne veut pas dire la même chose que 20 % tous canaux confondus.
  4. Comment traiter les remboursements ? Comparer le brut GA4 (qui inclut des remboursements futurs jamais renvoyés) au net SFCC (qui déduit les remboursements au fil de l’eau) revient à comparer des choses incompatibles. Soit vous alignez GA4 en implémentant les événements refund, soit vous comparez sur le brut confirmé SFCC, qui correspond à l’instantané de GA4.

Diagnostic pratique : vos premières requêtes BigQuery

Quand l’export GA4 et les données SFCC sont dans BigQuery, lancez cette séquence avant de construire quoi que ce soit dans Looker. La première compare les volumes quotidiens (commandes web seulement) :

SELECT
  date,
  SUM(ga4_orders)                  AS ga4_orders,
  SUM(sfcc_orders)                 AS sfcc_orders,
  SUM(sfcc_orders) - SUM(ga4_orders) AS delta,
  ROUND(
    (SUM(sfcc_orders) - SUM(ga4_orders))
    / NULLIF(SUM(sfcc_orders), 0) * 100, 1
  )                                AS gap_pct
FROM (
  -- GA4 purchases
  SELECT
    PARSE_DATE('%Y%m%d', event_date)          AS date,  -- event_date is a YYYYMMDD string
    COUNT(DISTINCT ecommerce.transaction_id)  AS ga4_orders,
    0                                         AS sfcc_orders
  FROM `project.analytics_XXXX.events_*`
  WHERE event_name = 'purchase'
    AND _TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY))
  GROUP BY 1
  UNION ALL
  -- SFCC web orders only
  SELECT
    DATE(created_at),
    0,
    COUNT(DISTINCT order_id)
  FROM `project.sfcc.orders`
  WHERE channel IN ('web', 'storefront')
    AND status NOT IN ('cancelled', 'fraud', 'test')
    AND DATE(created_at) >= DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)
  GROUP BY 1
)
GROUP BY date
ORDER BY date;
-- Interpretation:
-- Consistent gap: structural issue (tracking quality, consent mode)
-- Spiky gap: event-based issue (deployment broke tag on specific day)
-- Rolling 1-2 day offset: timing mismatch between systems

La deuxième requête décompose l’écart de revenu par mois (commandes SFCC, revenu brut et net, commandes GA4 appariées, deltas brut et net, taux d’appariement et part de commandes sans correspondance), en joignant sur LOWER(TRIM(order_id)) = LOWER(TRIM(transaction_id)). La troisième fait la même chose par catégorie de produit. Une catégorie au taux d’appariement systématiquement bas peut avoir un tag cassé sur ses pages produit, se vendre surtout en hors ligne ou en B2B, ou suivre un tunnel de paiement dont le déclencheur manque.

La suite de la série

Sources

Pour aller plus loin, lisez la version complète de l’article (en anglais) : Why GA4, SFCC and Offline Orders Will Never Match — And What That Gap Actually Tells You.

Besoin d’aide sur ce sujet ? Consultant GA4 et audit analytics.

Vous doutez de votre tracking ?

Réserver un appel Ou commencez par l’audit analytics gratuit →