GA4 Source/Support Not-Set : Solutions à tester

Qu’est-ce que le “not set” dans GA4 ?

Dans Google Analytics 4, “not set” n’est pas un bug mystique, c’est un aveu brutal : GA4 n’a pas la moindre idée d’où vient votre trafic.
C’est l’équivalent analytique de “je sais pas, j’étais pas là”.

Concrètement, dans vos rapports d’acquisition, la colonne Source / Support affiche “(not set)” quand les informations censées identifier l’origine du visiteur — d’où il vient, comment il est arrivé — sont introuvables ou perdues en route. Résultat : au lieu d’avoir un beau “google / organic” ou “newsletter / email”, vous vous retrouvez avec… rien.

Pourquoi c’est grave ? Parce que l’attribution disparaît. Et sans attribution, votre tableau de bord devient un roman policier où le coupable a été effacé des caméras. Vous perdez la trace des campagnes, le ROI devient un concept philosophique, et vos décisions marketing se basent sur des chiffres aussi fiables qu’une horloge fondue de Salvador Dalí.

Erreur classique : accuser Google. Mauvaise nouvelle, 80 % du temps, ce n’est pas Google le problème. C’est votre implémentation. Ou celle de votre agence. Ou celle du développeur qui, persuadé d’optimiser, a déclenché un tag avant le tag principal, comme on démarre une voiture avant d’avoir mis l’essence.

En clair :

Formez-vous à Google Analytics !

Maîtriser Google Analytics est crucial pour comprendre votre audience, optimiser vos campagnes, améliorer l'expérience utilisateur et mesurer vos conversions... Gagnez du temps avec nos formations Google Analytics.

  • “Not set” = données d’origine perdues.
  • Impact = attribution faussée, KPIs inutilisables, décisions bancales.
  • Cause principale = configuration ou déclenchement technique mal pensé.

C’est rarement une fatalité, mais c’est souvent un mélange explosif de mauvais timing, mauvaise config, et mauvaise communication.

Hypothèse 1 : Mauvais ordre de déclenchement des tags ga4

Un système de mesure, c’est d’abord un ordre de marche. En GA4, la balise de configuration ouvre la session, dépose les identifiants, prépare le contexte. Les event tags racontent ensuite ce qui se passe. Inversez l’ordre, et vous envoyez des événements sans identité. Résultat : source / support perdus, sessions éclatées, (not set) qui grimpe.

Le problème (factuel, pas philosophique)

  • Event avant config : un purchase ou un generate_lead part en éclaireur pendant que la config roupille.
  • Conséquence immédiate : pas de session_id valable, pas d’héritage de campagne → (not set) dans Acquisition.
  • Portrait-robot : vous voyez des événements dans DebugView, mais pas de session_start juste avant.

La solution courte

  • La config GA4 doit partir en premier. Toujours.
  • Les events attendent. Ils se déclenchent après la config, et idéalement dans une séquence forcée.

Implémentation propre dans gtm web

  1. Balise GA4 Configuration
    • Déclencheur : Initialization – All Pages (pour partir le plus tôt possible).
    • Consent Mode : si CMP, mettez la CMP en Consent Initialization, puis conditionnez la config à l’accord, ou acceptez le mode “pings” en connaissance de cause.
    • Option utile en SPA : send_page_view: false + envoi manuel du page_view (évite des vues fantômes).
  2. Balises GA4 Event
    • Déclencheurs : All Pages, clics, dataLayer… mais jamais sur Initialization.
    • Tag sequencing : Advanced Settings → Tag Sequencing → Fire a tag before this tagvotre GA4 Configuration.
    • En server-side : renseignez Server Container URL partout (config et events).
  3. Anti-patterns à bannir
    • Event en Initialization.
    • Config en Page View et events en DOM Ready (ça peut encore partir avant).
    • Mélange GTM + gtag hard-codé qui tire des events avant la config.

Variante si vous utilisez gtag.js “hard-codé”

L’ordre des appels doit être configevent. Exemple minimal correct :

<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXX', {
// en server-side : forcez le transport via votre endpoint
transport_url: 'https://collect.votredomaine.com'
});
// Les events viennent APRÈS la config :
gtag('event', 'generate_lead', {value: 1});
</script>

Si la page est SPA, envoyez manuellement un page_view à chaque changement de route, après la config.

Diagnostic express (2 minutes)

  • GTM Preview + GA4 DebugView : sur une page fraîche, l’ordre attendu est session_startpage_view → vos events.
  • Onglet Réseau : filtrez g/collect. Le premier hit doit être en=session_start. Si un event part avant, l’ordre est mauvais.
  • Rapport Acquisition : filtrez un event clé. Si (not set) chute brutalement après ré-ordonnancement, vous avez trouvé le coupable.

Cas particuliers à ne pas louper

  • CMP lente : si la config attend 2 secondes le consentement, l’utilisateur peut cliquer et déclencher des events “trop tôt”. Solution : déclenchez la CMP en Consent Initialization et réduisez la latence.
  • SPA : première charge = config + page_view. Changements de route = page_view manuel. Un seul session_start au tout début.
  • Server-side : sans server_container_url homogène, certains hits partent en direct, d’autres via serveur → ordre et identités cassés.

Check-list “zéro not set” pour l’ordre de tir

  • Config GA4 en Initialization
  • Events jamais en Initialization
  • Tag sequencing activé (event → “fire GA4 config before”)
  • CMP en Consent Initialization puis config conditionnée
  • En server-side : Server Container URL présent sur toutes les balises
  • SPA : page_view manuel sur les routes, send_page_view maîtrisé

Aphorisme utile : “On n’appuie pas sur le déclencheur avant d’armer la mesure.” Une fois l’ordre respecté, la source et le medium reviennent sagement, et vos rapports cessent de faire du dadaïsme.

Hypothèse 2 : Implémentation serveur-side mal configurée

Le server-side GTM, c’est un proxy propre pour vos hits. À une condition non négociable : tout doit passer par lui. Le petit paramètre qui fait la loi s’appelle server_container_url (côté GTM Web) — alias l’adresse de votre endpoint (https://collect.votredomaine.com). Oubliez-le sur un seul tag, et vous créez des hits qui partent directement chez Google pendant que le reste passe par votre serveur. Mélange des genres = sessions qui se découpent, contextes perdus, et une moisson de (not set).

Pourquoi l’oubli de server_container_url casse l’attribution

  • Deux routes, deux identités.
    Le conteneur serveur peut gérer un client_id first-party (FPID) et uniformiser les cookies. Un hit envoyé en direct (sans passer par le serveur) n’a pas ce même identifiant. Résultat : nouvelle session, parfois sans session_id cohérent → événements orphelins → (not set).
  • Ordre et timing désalignés.
    Les hits web (via serveur) et les hits directs n’arrivent pas dans la même chronologie technique. GA4 ne les regroupe pas proprement → perte de la source / medium héritée.
  • Configs divergentes.
    Côté serveur, vous appliquez souvent des règles (enrichissement, filtres, réécriture) qui n’existent pas quand un hit part en direct. Incohérence = attribution bancale.

Symptômes typiques

  • La majorité des événements est OK, une fraction aléatoire tombe en (not set).
  • L’exploration en temps réel montre des hits qui pointent tantôt vers https://collect.votredomaine.com/g/collect, tantôt vers https://www.google-analytics.com/g/collect.
  • En environnement avec Server-Managed Client ID (FPID) : explosion des self-referrals ou sessions doublées dès qu’un hit file en direct.

La bonne pratique (pas “optionnelle”) : homogénéiser partout

  1. Dans GTM Web → balise GA4 Configuration
    • Renseignez Server Container URL :
      https://collect.votredomaine.com
    • Activez le tag sequencing pour forcer cette config avant tous les events.
  2. Dans toutes les balises GA4 Event
    • Ajoutez Server Container URL (même valeur).
    • Oui, l’héritage “devrait” suffire ; non, on ne mise pas une attribution dessus.
  3. Si vous avez du gtag.js “hard-codé” dans le code source
    • Ajoutez le transport côté gtag : htmlCopyEdit<script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-XXXXXXX', { transport_url: 'https://collect.votredomaine.com' }); </script>
    • Ou mieux : supprimez le hard-code et migrez tout dans GTM Web.
  4. Measurement Protocol (serveur → GA4)
    • Réutilisez le même couple client_id + session_id que la session web active.
    • Si vous utilisez FPID côté serveur, assurez la cohérence côté web (tous les hits via le serveur, jamais en direct).
  5. DNS & cookies
    • Pointez collect.votredomaine.com vers votre conteneur serveur (A/AAAA ou CNAME propre).
    • Si vous utilisez FPID, validez que le cookie first-party est bien posé sur le bon domaine (et TTL attendu).
  6. Exclusion d’auto-référent
    • Ajoutez votre sous-domaine serveur dans Admin → Flux de données → Liste des références non désirées pour éviter que collect.votredomaine.com apparaisse comme source parasite.

Contrôle qualité (5 minutes chrono)

  • Network (onglet Réseau) : filtrez g/collect. Tous les appels doivent cibler votre domaine serveur. Zéro appel direct vers google-analytics.com.
  • DebugView GA4 : vérifiez que session_start puis page_view et vos events arrivent dans la même session.
  • Journal serveur (GTM Server) : le client GA4 doit traiter 100 % des hits. Les 404/Pass-through = alerte.
  • Comparatif avant/après : le taux de (not set) en Acquisition doit chuter après homogénéisation. Mesurez hors 48 h pour éviter le bruit d’ingestion.

Cas tordus (et correctifs)

  • Mix GTM Web + vieux script GA “planqué”
    → Fouillez le code, CMS, balises inline. Un seul chemin autorisé : via le serveur.
  • CMP/Consent lancée après la config
    → Lancez la CMP en Consent Initialization, puis la config GA4 conditionnée ; le serveur ne sauvera pas un hit lancé trop tôt… ou trop tard.
  • SPA (React/Vue) + server-side
    → Première vue : config + page_view en Initialization (via serveur). Changements de route : events manuels, toujours via serveur.

Mini tableau mémo

ErreurSymptômeCorrectif
server_container_url manquant sur 1+ tagsPics de (not set) aléatoiresRenseigner l’URL sur toutes les balises (config + events)
gtag hard-codé sans transport_urlRequêtes mixtes (serveur + direct)Ajouter transport_url ou retirer le hard-code
FPID activé + hits directs résiduelsSessions dupliquées, self-referralsForcer 100 % des hits via serveur
MP sans client_id/session_id webÉvénements hors session → (not set)Passer les IDs web au backend, aligner MP

Aphorisme utile : “Une seule porte d’entrée, sinon c’est la fête du slip.”
Traduction pro : un endpoint unique, cohérent, obligatoire. Quand tout transite par votre conteneur serveur, l’attribution redevient lisible, et “(not set)” retourne à sa niche.

Hypothèse 3 : Measurement protocol mal utilisé

Le Measurement Protocol est l’API qui permet d’envoyer des événements GA4 depuis un serveur. Utile pour compléter une session web avec des infos back-office (paiement confirmé, stock, CRM). S’il manque les bons identifiants de session/utilisateur, vos hits deviennent des fantômes et l’acquisition finit en (not set).

Les erreurs classiques (qui ruinent l’attribution)

  • Client ID inventé
    Non, client_id: "1234" ne “marchera pas”. GA4 attend le même client_id que celui posé côté navigateur. Sinon, impossible de rattacher l’événement à la bonne personne → orphelin.
  • Session ID inexistant… ou en texte
    Le session_id doit être numérique et réel (celui de la session en cours). Un session_id: "abc123" ou imaginaire ne sera pas accepté ou ne rattachera rien → (not set).
  • session_start manquant
    Le MP ne “crée” pas magiquement une session exploitable. Si vous envoyez un événement serveur avant qu’une session web ait démarré (ou longtemps après), rien à raccrocher → (not set). Évitez d’“émuler” session_start via MP : ce n’est pas fiable, laissez le web le générer.
  • Horodatage hors fenêtre
    Un timestamp_micros trop ancien (> 72 h) ne sera pas rattaché à la session passée. Même combat : (not set) ou hit ignoré.
  • Payload incomplet
    Oublier engagement_time_msec (≥ 1) ou mélanger de mauvais measurement_id/api_secret peut faire jeter le hit. Ce n’est pas “not set”, c’est “pas pris”.

Comment éviter le massacre : récupérer les bons IDs depuis le cookie GA

Objectif : envoyer le même client_id et le session_id actif que la couche web. Deux options simples.

Option A — côté web (recommandée), puis passez au serveur :

<script>
// Récupérer le client_id via gtag (GA4 doit être chargé)
gtag('get', 'G-XXXXXXXX', 'client_id', function(cid) {
// exposez cid à votre backend (XHR, header, dataLayer, etc.)
console.log('client_id', cid);
});

// Récupérer le session_id via le cookie _ga_<MEASUREMENT_ID>
(function() {
const name = '_ga_XXXXXXXX'; // _ga_<MEASUREMENT_ID>
const cookie = document.cookie.split('; ').find(c => c.startsWith(name + '='));
if (!cookie) return;
const val = decodeURIComponent(cookie.split('=')[1]);
// La valeur contient des paires clé=valeur, cherchez "sid"
// Exemple (simplifié): GS1.1.1723549876.1.1.1723549876.0.0.0
// Certains environnements exposent sid séparément; sinon, lisez-le via l'API web GA4 si dispo.
})();
</script>

Astuce pratique : beaucoup d’implémentations exposent sid via l’API web (variables GTM, DataLayer). Sinon, stockez le sid (session id) quand GA4 déclenche session_start et transmettez-le au backend pendant la session (cookie first-party, en-tête, champ masqué).

Option B — via cookie _ga (fallback)
Le cookie _ga contient le client_id sous forme xxxxxxxxxx.yyyyyyyyyy (deux entiers séparés par un point). Pour le session_id, préférez la valeur sid du cookie _ga_<MEASUREMENT_ID> quand elle est accessible. Évitez de “deviner” : un sid faux = (not set).

Exemple de requête Measurement Protocol correcte

-X POST "https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXXXXX&api_secret=YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"client_id": "1234567890.987654321",
"timestamp_micros": 1723549876000000,
"non_personalized_ads": false,
"events": [{
"name": "purchase_server",
"params": {
"session_id": 1723549,
"session_number": 3,
"transaction_id": "ORD-5842",
"value": 129.9,
"currency": "EUR",
"engagement_time_msec": 1
}
}]
}'

Points clés :

  • client_id = celui du navigateur (pas un ID CRM).
  • session_id = numérique et actif au moment de l’événement web correspondant.
  • timestamp_micros = dans la fenêtre des 72 heures et cohérent avec la session.
  • engagement_time_msec ≥ 1 pour éviter les rejets silencieux.
  • Ne taggez pas ça en “conversion” si vous n’êtes pas certain du rattachement à une vraie session.

Recette simple et robuste (web ↔ serveur)

  1. Au session_start web, lisez et stockez côté client : client_id, session_id, session_number, l’horodatage.
  2. Exposez-les à votre backend (en-tête HTTP, token, champ masqué sur le checkout).
  3. Côté serveur, quand vous envoyez un hit MP (ex. confirmation de paiement) :
    • réutilisez exactement ces valeurs,
    • ajoutez timestamp_micros (temps réel ou léger backdating),
    • mettez engagement_time_msec: 1.
  4. Logguez la requête et la réponse MP (pour auditer les ratés).
  5. Vérifiez dans DebugView : l’événement MP doit tomber dans la même session (même sid) que le page_view/click correspondant.

Anti-patterns à bannir

  • “On met user_id, ça suffira” → non, user_id n’aide pas l’attribution si client_id/session_id sont faux.
  • “On envoie MP d’abord, le web suivra” → vous fabriquez des hits hors session.
  • “On crée un faux session_start côté serveur” → comportement non garanti, et souvent contre-productif.

Aphorisme utile : “Un hit sans client ni session, c’est une bouteille à la mer. Elle flotte, mais elle n’arrive jamais au port.”
Respectez le duo client_id + session_id réels, gardez l’horloge dans les clous, et votre Measurement Protocol cessera d’alimenter le cimetière des (not set).

Hypothèse 4 : Problème de l’event “session_start” manquant

session_start est l’impulsion électrique du cerveau GA4. Sans elle, pas de session, pas d’attribution, juste des événements errants classés en (not set). Quand ça disparaît, ce n’est pas “le destin”, c’est une configuration qui boîte.

Ce qui peut le faire sauter

  • Consentement mal géré (CMP / Consent Mode v2)
    Si analytics_storage est denied ou accordé trop tard, GA4 ne lit/écrit pas les cookies au bon moment. Résultat : pas de session exploitable, donc pas de session_start.
    Réflexe : en GTM, déclencher la CMP en “Consent Initialization”, puis la config GA4 uniquement après consentement accordé (ou avec un mode “pings” assumé et analysé comme tel).
  • Ordre de tags inversé
    La config GA4 doit partir avant tout event. Si un event part en Initialization et la config en Page View, vous tirez dans le vide.
    Réflexe : config GA4 sur Initialization, events après (tag sequencing activé).
  • Bloqueurs / DNS filtrants
    Brave, uBlock, Pi-hole, DNS “privacy” : ils coupent gtag.js ou g/collect. Si rien n’atteint GA, session_start n’existe pas.
    Réflexe : passer par server-side tagging sur un sous-domaine first-party (collect.votredomaine.com) et renseigner transport_url. Testez avec un navigateur “propre” et un navigateur “blindé”.
  • Lenteur et précarité réseau
    Sur mobile et réseaux faibles, l’utilisateur repart avant que la config GA4 ait tiré.
    Réflexe : déclenchez la config le plus tôt possible (Initialization), nettoyez le bloat JS, mesurez le TTFB / LCP. Un tag qui démarre trop tard ne démarre pas.
  • SPA / navigation côté client mal trackée
    Sur React/Vue/Angular, si la première vue n’envoie pas le bon enchaînement (config + page_view) ou si les changements de route ne sont pas gérés, la session peut rester fantôme.
    Réflexe :
    • première charge : config GA4 + (optionnel) send_page_view: true
    • changements de route : event page_view manuel avec page_location/page_referrer.
    • GTM : déclencheur History Change + variables d’URL.
  • Measurement Protocol envoyé trop tôt / mal renseigné
    Un événement serveur arrive avant qu’une session web existe, ou sans client_id / session_id réels → impossible à rattacher.
    Réflexe : ne postez via MP qu’avec client_id + session_id d’une session active (ou assumez que c’est hors session et ne marquez pas conversion). Utilisez timestamp_micros pour caler l’ordre dans la fenêtre des 72 h.
  • Cookies inaccessibles ou isolés
    Iframes sandbox, sous-domaines sans cross-domain configuré, ou politiques de cookies trop restrictives : GA4 ne peut pas persister l’ID → sessions volatiles.
    Réflexe : configurer cross-domain linking si besoin, éviter les iframes sandbox pour la page de tracking, vérifier le domaine du cookie.
  • Config du site qui “mange” l’événement
    Pages qui redirigent instantanément, auto-refresh agressif, scripts qui écrasent dataLayer… L’événement n’a pas le temps de vivre.
    Réflexe : stabiliser le DOM avant redirection, push dans dataLayer sans le réinitialiser, éviter les hard-refresh côté JS.

Le seuil de douleur

  • 1–2 % de sessions sans session_start : bruit acceptable.
  • > 5 % : problème structurel. Auditez d’urgence l’enchaînement Consent → Config → Events et les conditions réseau/navigateur.

Check express (5 minutes)

  1. GTM Preview + GA4 DebugView
    Rechargez une page. Vous devez voir, en tête, session_start suivi de page_view. S’il manque, regardez l’ordre et les triggers.
  2. Onglet Réseau
    Filtrez sur g/collect. Vérifiez l’event en=session_start et la présence de sid (session id) et sct (session count). Absents = config trop tard/événement bloqué.
  3. CMP
    Refaites le test en refusant puis en acceptant. Si session_start n’apparaît qu’après un long délai post-consentement, ajustez le chaînage : CMP en Consent Init, GA4 en Initialization conditionnée.
  4. Bloqueurs
    Test A/B : navigateur “propre” vs navigateur avec uBlock/Brave. Si session_start disparaît, migrez vers server-side + sous-domaine first-party et renseignez transport_url.
  5. SPA
    Naviguez sur trois routes. Vous devez voir un seul session_start (au début), puis des page_view à chaque route. Pas de session_start ? Votre première vue n’est pas correctement initialisée.

Bonnes pratiques qui évitent 80 % des cas

  • Config GA4 sur Initialization, events ensuite, tag sequencing activé.
  • Consent mode maîtrisé : n’attendez pas 2 s après le clic pour lancer GA4, et ne déclenchez pas d’events avant consentement accordé si vous voulez des sessions exploitables.
  • Server-side : server_container_url partout, endpoint HTTPS first-party, transport_url côté web.
  • MP discipliné : toujours client_id réel + session_id numérique réel, sinon vos hits vivent hors session.
  • Évitez les audience triggers pour générer des events (asynchrones = hors session).
  • Analysez hors 48 h pour juger du vrai taux (les données fraîches sont parfois incomplètes).

Indices concrets d’un session_start absent

  • Acquisition : hausse de (not set) sur des événements pourtant “on-site”.
  • DebugView : suites d’événements sans le drapeau session_start au début.
  • Network : pas de requête en=session_start au premier hit, sid manquant sur les suivants.

Deux aides de terrain

  • Récupérer le client_id côté web (utile pour MP aligné) : htmlCopyEdit<script> // nécessite gtag déjà chargé gtag('get', 'G-XXXXXXX', 'client_id', (cid) => { console.log('client_id', cid); }); </script>
  • Vérifier le session_id sans dev : Ouvrez DevTools → Application/Stockage → Cookies → _ga_<MEASUREMENT_ID> : cherchez sid (numérique). S’il n’apparaît jamais à la première page, la config ne s’exécute pas assez tôt… ou pas du tout.

Aphorisme pour route : “Une session sans session_start, c’est un alibi sans témoin.” Assurez l’ordre, respectez le consentement, domestiquez les bloqueurs, et session_start revient sagement prendre sa place en tête de vos événements.

Hypothèse 5 : Audience triggers : le faux bon plan

Au départ, l’idée paraissait élégante : déclencher automatiquement un événement quand un visiteur entre dans une audience. Pas de condition tarabiscotée dans GTM, pas de code côté site, juste un “si l’utilisateur correspond à X, GA4 émet l’événement Y”. Sur le papier, c’est du tracking sans friction. Dans la vraie vie, c’est un lance-patate qui tire sur votre attribution.

Pourquoi ça semblait malin

  • Centralisation : on définit la logique une fois (dans Admin > Audiences), et on la réutilise partout.
  • Granularité : on peut combiner des conditions complexes (fréquence, valeur, séquences) sans toucher au front.
  • Zéro dev : promesse irrésistible pour les équipes déjà surchargées.

Pourquoi ça flingue l’attribution

  • Événements détachés de toute session : l’évaluation d’une audience n’est pas synchrone avec l’action de l’utilisateur. Elle peut se produire après coup (quelques minutes… ou plus). Résultat : l’“audience trigger” tombe hors du cadre de la session réelle. Sans session active, pas de source / support qui tienne. Bonjour “(not set)”.
  • Contexte absent : ces événements n’arrivent pas à la suite d’un page_view ou d’un vrai hit utilisateur. Ils sont “générés” par GA4, sans les paramètres de contexte habituels (chemin, campagne, etc.). Vous récoltez un événement, mais vous perdez le pourquoi et le d’où.
  • Bruits en acquisition et en conversions : si vous marquez ces événements comme conversions, vous créez des conversions non attribuables. Ça gonfle le compteur, ça vide le sens. Pire, ça peut fausser vos modèles d’enchères si vous les exportez vers Ads.
  • Temporalité bancale : l’entrée dans l’audience peut se produire une fois la session terminée (ou à la session suivante). Vous pensez “conversion immédiate”, vous mesurez en fait un statut d’utilisateur arrivé en retard.

Aphorisme utile : “Si ce n’est pas déclenché par l’utilisateur, ce n’est pas un événement, c’est une notification.” Les notifications, GA4 sait les stocker, mais il ne sait pas leur inventer une source.

Les symptômes sur vos rapports

  • Une poignée d’événements au nom souvent “propre” (ex. au_entered_lead_audience) avec (not set) en Source/Support.
  • Des conversions qui montent, mais aucune campagne ne peut les revendiquer sans se racler la gorge.
  • Des écarts étranges entre explorations (centrées comportement) et rapports d’acquisition (centrés attribution).

La solution pragmatique

  • Supprimer les audience triggers pour la mesure. Gardez les audiences pour le remarketing et la segmentation, pas pour émettre des événements.
  • Remplacer par de vrais événements côté site / GTM : déclenchez generate_lead, purchase, sign_upau moment où l’action se produit, avec le contexte de session intact.
  • Si vous avez absolument besoin d’un “entrée dans l’audience” :
    • Envoyez-le côté client au moment où la condition devient vraie (ex. après le 3e achat, après N visites), pas via Audience Trigger.
    • Ou n’en faites pas un événement : stockez un user_property (ex. is_high_value = true) et servez-vous-en dans l’analyse et l’activation.
  • Désactivez la case “Marquer comme conversion” pour tout événement qui viendrait d’un audience trigger hérité. Une conversion doit naître d’une action, pas d’un recalcul asynchrone.

Procédure d’assainissement en 10 minutes

  1. Audit : Admin > Audiences → ouvrez chaque audience → cherchez la section Audience trigger.
  2. Inventaire : listez les événements auto-déclenchés (préfixez-les au_ si ce n’est pas déjà le cas, pour les repérer).
  3. Suppression : désactivez/supprimez le trigger dans chaque audience.
  4. Conversions : Admin > Conversions → décochez celles qui correspondent à des au_*.
  5. Remplacement : implémentez l’événement équivalent dans GTM/gtag avec un déclencheur basé sur l’action réelle.
  6. Vérification : DebugView → contrôlez que l’événement part dans la même session que l’action.
  7. Surveillance : Rapport d’acquisition → filtrez sur l’événement remplacé → not set doit chuter vers zéro (hors bruit de fond inhérent).

Alternatives propres selon le besoin

  • Scoring / statut utilisateur : user_properties + BigQuery (pas d’événement artificiel).
  • Cross-device / back-office : Measurement Protocol, mais avec client_id + session_id d’une session active si vous voulez de l’attribution ; sinon, assumez que c’est hors session et n’en faites pas une “conversion”.
  • Campagnes : gardez les conversions sur les événements natifs (clic, envoi, paiement). Attribuez les statuts d’audience au CRM, pas au moteur d’attribution.

Résumé sec : les audience triggers étaient une bonne idée pour marketer pressé, pas pour mesure propre. Ils génèrent des événements qui arrivent en retard, sans session, donc sans attribution. Remplacez-les par des déclenchements côté site, gardez les audiences pour cibler, et votre “not set” s’évaporera aussi vite que la patience d’un analyste devant un funnel en pointillés.

Hypothèse 6 : Paramètres utm incorrects

Les UTM sont la ceinture de sécurité de l’attribution. Mal bouclées, vous traversez le pare-brise et atterrissez en (not set). Rappel de base : utm_source, utm_medium, utm_campaign sont obligatoires. Le reste (utm_term, utm_content, utm_id) est utile, mais jamais un substitut.

Que se passe-t-il quand ils sont manquants ou incohérents ?

  • utm_source absent → GA4 ne sait pas “qui” envoie le trafic. La dimension Source/Support bascule en (not set) ou se rabat sur “referral/direct” selon le contexte.
  • utm_medium absent ou exotique → pas de mappage correct vers les Default Channel Groups. Vos clics “payants” finissent en “Unassigned”, votre reporting devient un cubisme douteux.
  • utm_campaign manquant → la campagne n’existe pas dans les rapports. Utile si vous aimez jeter de l’argent sans le retrouver.
  • Typos (utm-sorce, utm_meduim) → GA4 ne corrige pas votre orthographe. C’est ignoré, point.
  • Casse et variations (Email vs email, Facebook vs facebook) → fragmentation des rapports, impossible d’additionner proprement.
  • UTM sur des liens internes → vous vous ré-attribuez la session au milieu du parcours. Bonjour les auto-référents, au revoir l’attribution initiale.
  • Redirections qui suppriment la query string → vous posez des UTM… que le serveur jette à la poubelle. Résultat : (not set).

Conventions simples qui évitent 90 % des dégâts

  • Toujours les 3 : utm_source, utm_medium, utm_campaign.
  • Minuscules partout (source, medium, campaign).
  • Mediums “canoniques” (alignez-les sur les Channel Groups par défaut de GA4) :
    • cpc ou ppc → Paid Search
    • paid_social → Paid Social
    • social → Organic Social (selon source)
    • email → Email
    • display → Display
    • affiliate → Affiliates
    • referral → Referral
  • Sources claires : google, bing, facebook, instagram, linkedin, newsletter_nom, partner_nom.
  • Campagne stable : campagne-printemps-2025 (évitez espaces/accents ; tirets courts).
  • N’utilisez jamais d’UTM en interne (navigation, boutons, bannière maison).
  • Conservez les UTM à travers les redirections (sinon, vous mesurez… le néant).

Exemples concrets

Correct (email)

https://exemple.com/offre?utm_source=newsletter&utm_medium=email&utm_campaign=lancement-produit

Correct (paid social)

https://exemple.com/offre?utm_source=facebook&utm_medium=paid_social&utm_campaign=retargeting-q3

À éviter (medium vague)

...utm_medium=campaign  // pas mappé → “Unassigned”

À proscrire (lien interne)

/panier?utm_source=menu&utm_medium=internal&utm_campaign=nav  // casse l’attribution

Bonus utiles mais optionnels

  • utm_id : identifiant de campagne stable (alimentation de la dimension ID de campagne). Pratique pour regrouper variantes créatives sous une seule campagne.
  • utm_content : différencier A/B créa, emplacements, formats.
  • utm_term : mots-clés pour Paid Search hors auto-tagging.

Audit UTM : méthode express, résultat propre

  1. Inventaire des sources de liens
    Ads (Google, Meta, LinkedIn), newsletters, CRM, partenaires/affiliation, SMS, push, influence, QR codes, PDF, signatures email.
  2. Extraction des URLs
    • Depuis vos plateformes (exports),
    • Depuis GA4 via l’exploration “Landing page + requête” pour voir les UTM réellement utilisés à l’entrée.
  3. Contrôle de présence et d’orthographe
    • Cherchez utm_source=, utm_medium=, utm_campaign= (exact, pas d’underscore/typo).
    • Repérez les casse incohérentes (Email vs email).
  4. Validation des mediums
    • Comparez vos valeurs à la liste “canonique” ci-dessus.
    • Créez si besoin un Custom Channel Group dans GA4 pour mapper proprement des mediums maison, mais soyez constants.
  5. Test des redirections
    • Cliquez sur chaque URL taguée → la page finale doit conserver les UTM.
    • Si vous perdez les paramètres, corrigez le serveur :
      • Nginx : rewrite ^/old$ /new?$args permanent;
      • Apache : RewriteRule ^old$ /new [R=301,L,QSA]
  6. Sanctions
    • Supprimez tous les UTM internes.
    • Normalisez par lot : remplacez Emailemail, Paid Socialpaid_social, etc.
  7. Gouvernance
    • Rédigez une nomenclature d’une page avec exemples approuvés.
    • Fournissez un générateur UTM (Google Sheet / petit outil) qui impose minuscules et champs obligatoires.

Mini check-list “prêt à publier”

  • Les 3 UTM obligatoires sont présents.
  • utm_medium appartient à la liste validée.
  • Valeurs en minuscules, sans espaces, sans accents.
  • L’URL finale conserve la query string après redirection.
  • Aucun UTM utilisé sur des liens internes.
  • utm_id appliqué si vous avez des variantes créatives nombreuses.

Détection des dégâts dans ga4 (pour agir vite)

  • Acquisition > Trafic : filtrez par Session source/medium = (not set) et inspectez les Pages de destination correspondantes.
  • Explorations : tableau avec Session source/medium, Session campaign, Landing page + requête. Les lignes avec ? vide côté requête mais campagne renseignée = UTM perdus en route.
  • Tendance : si (not set) explose le jour même d’un envoi newsletter ou d’une campagne, vos UTM sont mal formés ou écrasés par une redirection.

Erreurs → symptômes → correctifs (mémo)

ErreurSymptôme dans GA4Correctif
utm_source manquant(not set) en Source/SupportAjouter utm_source (valeur claire, minuscule)
utm_medium non standardCanal = UnassignedRemapper sur cpc, email, paid_social, display, etc.
utm_campaign absentCampagnes videsRenseigner un nom stable (sans espaces)
Typos (utm-sorce)UTM ignorésCorriger à la source, outiller la saisie
UTM internesAuto-réattribution, self-referralsSupprimer, utiliser events/params internes
Redirection qui coupe la query(not set) malgré UTM posésConserver $args / QSA dans la règle serveur

Aphorisme pour conclure : “Une UTM mal fichue, c’est un alibi en Comic Sans.” Faites simple, faites constant, testez les redirections, et votre attribution cessera de jouer à cache-cache avec (not set).

Hypothèse 7 : Données récentes non traitées

Analyser aujourd’hui et hier dans GA4, c’est discuter avec un déménageur en plein carton : la moitié des infos n’est pas rangée. Les rapports standards ne sont pas en temps réel. La pipeline “intraday” remonte une partie des événements pendant la journée, puis la pipeline “daily” complète et corrige… jusqu’à 24–48 h après. Entre-temps, il y a des trous temporaires dans les dimensions d’attribution event-scoped (source, medium, campagne, channel). Traduction opérationnelle : ce qui n’est pas encore rattaché tombe plus souvent en (not set), puis “revient” quand le traitement quotidien passe. support.google.com+1

Conséquence directe : le “not set” gonfle artificiellement sur les fenêtres < 48 h. Quand les données “daily” arrivent, GA4 rattache mieux les événements à la bonne source/support et applique votre modèle d’attribution. Et ce n’est pas qu’un rattrapage : le crédit d’attribution de vos conversions peut évoluer jusqu’à 12 jours après l’événement, le temps que la modélisation finisse son boulot. Moralité : ne jugez jamais une campagne sur un jour ou deux, encore moins le lendemain matin. support.google.com

Côté BigQuery Export, même logique :

  • Les tables daily (events_YYYYMMDD) peuvent être ré-écrites jusqu’à 72 h pour intégrer des hits en retard (Measurement Protocol, SDKs).
  • Les tables intraday donnent de la fraîcheur, mais restent “provisoires”.
    Si vous faites vos dashboards sur BQ, gardez un lag d’au moins 48–72 h avant d’appeler un jour “figé”. support.google.com

Pourquoi cela fabrique du (not set) ?

  1. Les trafics sources au niveau événement arrivent parfois après coup ; tant qu’ils ne sont pas là, l’événement est compté mais sans attributions complètes. 2) Les pipelines intraday appliquent des règles plus strictes (cardinalité, agrégation) en attendant la “daily”, ce qui multiplie les “valeurs par défaut” et les cases vides. Résultat : l’acquisition se nettoie en différé. support.google.com

Ligne de conduite pragmatique

  • Exclure systématiquement J et J-1 de vos analyses d’acquisition. Focalisez-vous sur J-2 → J-31 pour la décision.
  • Pour les tableaux de bord, imposez un décalage fixe (ex. “derniers 7 jours hors 2 derniers jours”).
  • Si vous devez monitorer à chaud, utilisez Temps réel et DebugView pour la santé du tracking, mais jamais pour l’attribution. Les vrais rapports, c’est quand la “daily” est passée. support.google.com

Mémo express

Fenêtre analyséeCe qui se passeRisque sur “not set”Recommandation
Aujourd’hui / HierDonnées intraday partielles, trous temporaires dans source/mediumÉlevéNe pas conclure, monitorer seulement
J-2 → J-7Données daily, attribution plus stable (peut encore bouger)Faible à modéréOK pour reporting hebdo
J-8 → J-14Données stables, modélisation quasiment terminéeFaibleOK pour reporting mensuel
BigQuery intradayFrais, incompletÉlevéUtiliser pour QA/ops, pas pour décision
BigQuery daily (≥ 72 h)ConsolidéFaibleBase fiable pour analyses fines

Aphorisme utile : « La fraîcheur des données, c’est comme le fromage : trop frais, ça pique les yeux. » Laissez 48 h à GA4 pour lier correctement les événements à leurs sources/supports. Vous verrez le (not set) reculer tout seul, sans exorcisme, juste avec du temps de traitement.

Hypothèse 8 : Trafic spam/bots

Le (not set) peut exploser sans prévenir quand des bots arrosent vos endpoints. Ils ne portent pas d’UTM, ne déclenchent pas toujours session_start, et inondent vos rapports d’événements hors attribution. GA4 filtre déjà une partie des “bots connus” (IAB), mais ce filet a des mailles larges : ce qui n’est pas sur la liste passe. support.google.com

Signes d’alerte (simples, efficaces)

  • Pics soudains d’événements/sessions, souvent sur des heures creuses, sans campagne en cours.
  • “(not set)” massif dans Acquisition sur des événements pourtant “on-site”.
  • Pages de destination bizarres (URLs techniques, 404, endpoints d’API, pages cachées).
  • Pays/langues improbables, résolutions d’écran impossibles, user agents exotiques.
  • Self-referrals ou rafales sur la même route (ex : /cart) sans cheminement normal.

Mesures qui marchent (du plus proactif au plus réactif)

1) Activer une protection anti-bot au niveau CDN (Cloudflare & co.)

Objectif : bloquer/challenger les requêtes avant qu’elles n’atteignent votre site (et donc GA4).

  • Cloudflare attribue un bot score (1–99) à chaque requête ; scores bas = requêtes probablement automatisées. Les modèles par défaut permettent d’autoriser les bots vérifiés (Googlebot) et de challenger ou bloquer les autres selon un seuil, par exemple “< 30 = bot probable”. Cloudflare Docs+2Cloudflare Docs+2
  • Concrètement, créez une règle WAF : scssCopyEditif (cf.bot_management.score < 30) then Challenge or Block L’intérêt : vous nettoyez à la source, sans polluer GA4, tout en laissant passer les bons robots (SEO). Cloudflare Docs+1

Effet attendu : chute immédiate des pics, baisse du (not set) corrélée aux heures/segments ciblés par les règles.

2) Filtrer côté server-side tagging avec un “bot score”

Si vous utilisez GTM serveur, ajoutez une couche de tri avant d’émettre les hits GA4.

  • Hébergeurs sGTM comme Stape exposent des en-têtes type X-Device-Bot et X-Device-Bot-Score (1–100). Créez une Variable “Request Header” dans sGTM et n’exécutez pas vos tags si le score dépasse votre seuil (ex. > 90). stape.io+1

Pseudo-logique de déclencheur (sGTM) :

IF  RequestHeader.X-Device-Bot == 'true'  OR  RequestHeader.X-Device-Bot-Score >= 90
THEN Do not fire GA4 tag

Intérêt : vous évitez d’enregistrer l’événement côté GA4 tout en gardant la mesure côté serveur pour l’analyse forensique.

3) Filtrage IP dans GA4 (solution réactive)

Quand un lot d’IP vous attaque, isolez-le :

  • Admin → Flux de donnéesConfigurer les paramètres des tagsDéfinir le trafic interne : créez une règle “bots” et listez les IP (ou une regex).
  • Admin → Filtres de données → activez Internal traffic en Exclude.
    Méthode imparfaite (les IP changent), mais utile pour couper l’hémorragie pendant que le CDN/WAF se met en place. support.google.com

Workflow d’enquête (10 minutes, montre en main)

  1. Confirmer le bot burst
    Acquisition > Trafic → filtrez Session source/medium = (not set) → croisez avec Page de destination et Pays/UA. Si tout pointe vers la même route, c’est rarement humain.
  2. Inspecter le réseau
    Logs serveur ou CDN : mêmes IPs / ASNs / UA qui spamment ? Notez-les.
  3. Mitiger au périmètre
    Règle Cloudflare basée sur bot score + pays/ASNs suspect → Challenge/Block. Cloudflare Docs
  4. Durcir la collecte
    sGTM : ajoutez la condition “bot score” sur les triggers GA4. stape.io
  5. Purger le bruit rémanent
    GA4 : règle Internal traffic = bots + filtre Exclude (temporaire mais utile). support.google.com
  6. Vérifier le retour à la normale
    Suivez la part de (not set) par heure/jour (hors 48 h, traitement oblige). Si ça ne baisse pas, haussez le niveau (captcha, règles plus strictes). support.google.com

mémo décisions → effets attendus

ActionEffet sur botEffet sur “(not set)”
Règle bot score < 30 → challengeCDN (Cloudflare)Stoppe à la porteForte baisse immédiate
X-Device-Bot-Score ≥ 90 → ne pas tirer GA4sGTMÉvite l’enregistrementBaisse nette, surtout sur pics
Filtre IP “bots”GA4Coupe une vague cibléeBaisse partielle (réactive)
Laisser faire “IAB bots filtering”GA4 (auto)Filtre les connusInsuffisant contre bots récents

Rappel utile : GA4 exclut déjà automatiquement une partie du trafic bot/spider basé sur des listes “connues”. Si malgré tout (not set) grimpe, c’est au-delà de ces listes — il faut agir en amont (CDN/WAF) et au niveau collecte (sGTM). support.google.com

Deux garde-fous supplémentaires

  • Cachez vos endpoints : utilisez un sous-domaine first-party pour GA4 (server-side) et un transport_url pour éviter le repérage trivial de google-analytics.com.
  • Bloquez les référents pourris : ajoutez vos domaines techniques à la liste des références non désirées pour éviter les auto-référents en cascade.

Aphorisme pour finir : « Contre les bots, la meilleure attribution, c’est la porte d’entrée fermée. » Mettez le WAF devant, le score au milieu, et le filtre derrière. Votre (not set) retrouvera sa taille de bruit de fond.

    Conclusion

    “(not set)” n’est pas une fatalité. C’est un symptôme. Quand la source/support disparaît, ce n’est pas l’univers qui complote : c’est une chaîne de détails techniques mal ordonnés. Mauvais ordre des balises, server-side percé, Measurement Protocol fantaisiste, session_start absent, audience triggers asynchrones, UTM bancales, données trop fraîches, bots en goguette. Additionnez tout ça et vos rapports ressemblent à un roman noir sans coupable.

    L’approche “rustines” (un correctif par-ci par-là) ne marche pas. Elle déplace le problème. Ce qu’il faut, c’est un audit complet, court, précis, impitoyable avec les incohérences.

    Audit express (priorisé, exécutable)

    1. Fenêtre d’analyse
      • Écarter J et J-1. Travailler sur J-2 → J-31 pour juger du taux réel de (not set).
      • Objectif : éviter les faux “trous” d’ingestion.
    2. Ordre de tir (GTM Web / gtag)
      • Config GA4 en Initialization, events après (sequencing activé).
      • Objectif : session_start avant tout event. Taux de session_start manquants ≤ 2 %.
    3. Server-side homogène
      • server_container_url partout (config et events).
      • transport_url si gtag hard-codé.
      • Objectif : 100 % des hits via votre endpoint, zéro requête directe google-analytics.com.
    4. Measurement Protocol discipliné
      • Réutiliser client_id et session_id réels de la session web active (+ timestamp_micros cohérent, engagement_time_msec ≥ 1).
      • Objectif : 0 événement MP “hors session” marqué conversion.
    5. Consent & bloqueurs
      • CMP en Consent Initialization, GA4 déclenché en connaissance de cause.
      • Envisager server-side sur sous-domaine first-party pour limiter le blocage.
      • Objectif : sessions stables malgré privacy tools.
    6. SPA & navigation
      • Première charge : config + (éventuel) page_view.
      • Routes : page_view manuel avec page_location/page_referrer.
      • Objectif : un seul session_start au début, des vues nettes ensuite.
    7. UTM & canaux
      • Imposer les 3 obligatoires (utm_source, utm_medium, utm_campaign), minuscules, mediums canoniques.
      • Interdire les UTM internes.
      • Objectif : 0 “Unassigned”, 0 typos, 0 UTM perdus en redirection.
    8. Audience triggers
      • Supprimer les déclencheurs d’audience qui émettent des events.
      • Conserver les audiences pour la segmentation / activation, pas pour “fabriquer” des hits.
      • Objectif : plus d’événements asynchrones sans session.
    9. Anti-bot en amont
      • WAF/CDN (Cloudflare…) avec bot score → challenge/block.
      • En sGTM : ignorer les hits au-delà d’un seuil de score bot.
      • En GA4 : filtre IP (solution réactive).
      • Objectif : faire chuter les pics et la part de (not set) corrélée.
    10. Contrôles & seuils
    • DebugView : ordre session_start → page_view → events.
    • Network : premier hit = en=session_start avec sid/sct.
    • KPI de propreté : (not set) ≤ 1–2 % hors 48 h, stable par canal.

    Mémo “cause → symptôme → action”

    CauseSymptômeAction nette
    Event avant configEvents sans sid, (not set)Config en Initialization + sequencing
    server_container_url absentHits mixtes, sessions dupliquéesURL serveur partout + transport_url
    MP sans IDs réelsConversions hors attributionPasser client_id/session_id web au backend
    session_start manquantSuites d’événements orphelinsOptimiser ordre/consent, viser ≤ 2 % manquants
    Audience triggersEvents (not set) asynchronesSupprimer, remplacer par vrais events
    UTM foireux“Unassigned”, campagnes videsNormaliser sources/mediums/campagnes
    Données trop fraîches(not set) gonflé sur J/J-1Exclure 48 h des analyses
    BotsPics + (not set) massifWAF/CDN + score bot sGTM + filtres IP

    Livrables attendus (pour clore proprement)

    • Nomenclature UTM d’une page, générateur imposant les champs obligatoires.
    • Playbook GTM/gtag (ordre, sequencing, Consent Mode, SPA).
    • Checklist server-side (endpoint, cookies, exclusions de référents).
    • Recette MP (schéma d’IDs, journalisation, tests DebugView).
    • Règles WAF/CDN et conditions sGTM anti-bot.
    • Tableau de suivi du taux de (not set) par jour/canal (hors 48 h).
    Retour en haut
    Formations Analytics