quest_taux_consentement_bigquery_ga4.exe
_
□
×

Mesurer votre taux de consentement réel dans GA4 BigQuery

Votre CMP affiche un taux de consentement, GA4 BigQuery en montre un autre. 3 requêtes SQL pour obtenir votre vrai taux et pour détecter une bannière cassée.

bigquery consentement consent-mode ga4 privacy guide

Votre bannière vous annonce fièrement 72 % de consentement. Votre export GA4 BigQuery, lui, raconte une tout autre histoire. Et c’est BigQuery qui a raison. Tout le monde parle du Consent Mode comme d’une case à cocher dans GTM, presque personne n’explique comment lire le consentement dans les données brutes, là où il n’y a plus de marketing, juste des lignes et des champs. C’est exactement ce que je vais vous montrer : où se cache le consentement dans l’export GA4 BigQuery, et comment, en trois requêtes SQL prêtes à copier, calculer votre vrai taux de consentement par page, device et pays, chiffrer la part de trafic que vous ne voyez pas, et repérer une bannière cassée avant que vos conversions ne plongent.

Le timing n’est pas innocent. Depuis le 15 juin 2026, ad_storage gouverne seul ce qui remonte vers Google Ads, Google exploite l’adresse IP depuis le 3 août, et la règle des 6 mois du Digital Omnibus verrouille les refus plus longtemps. Autrement dit : chaque point de consentement perdu coûte plus cher qu’avant, et la première chose à faire avant de décider quoi que ce soit, c’est de chiffrer ce que vous perdez vraiment. Pas ce que votre outil de bannière veut bien vous dire.

Ce que votre CMP mesure, et ce que GA4 voit vraiment

Votre plateforme de consentement (CMP) compte ses propres clics : combien de visiteurs ont accepté, refusé ou ignoré le bandeau. C’est une mesure utile, mais c’est une mesure côté bannière. Elle ne dit rien de ce qui est réellement arrivé jusqu’à GA4 une fois le Consent Mode passé par là, les tags déclenchés (ou pas), les pings envoyés (ou pas). Entre les deux, il y a du JavaScript, des règles de déclenchement, des bloqueurs, des visiteurs qui partent avant d’avoir cliqué. Le chiffre de la CMP et le chiffre vu par GA4 ne sont pas le même chiffre, et ils divergent souvent de dix à vingt points.

Pourquoi faire confiance à BigQuery plutôt qu’à l’interface GA4 ? Parce que l’interface et l’API appliquent de la modélisation : Google reconstruit statistiquement une partie du comportement des visiteurs non consentants. L’export BigQuery, lui, ne modélise rien. Il contient les événements bruts, tels qu’ils sont arrivés. C’est brutal, c’est incomplet par design, mais c’est la vérité terrain. Quand vous voulez savoir qui a réellement consenti, c’est BigQuery qui tranche.

Où se cache le consentement : le champ privacy_info

Dans l’export GA4 BigQuery, le consentement vit dans un champ RECORD nommé privacy_info, présent sur chaque ligne d’événement. Il contient trois sous-champs :

ChampValeurs possiblesCe que ça signifie
privacy_info.analytics_storage"Yes", "No", nullConsentement au stockage analytics (cookies de mesure)
privacy_info.ads_storage"Yes", "No", nullConsentement au stockage publicitaire
privacy_info.uses_transient_token"Yes", "No", nullLié aux jetons temporaires du mode avancé

Premier piège à éviter : ce sont des chaînes de caractères, pas des booléens. On écrit where privacy_info.analytics_storage = 'Yes', surtout pas = true. La valeur "Yes" veut dire consentement accordé, "No" consentement refusé, et null signifie qu’aucun Consent Mode n’est implémenté ou que l’état est inconnu. Si vous ne voyez que des null, votre Consent Mode n’est pas câblé côté signal, et le reste de cet article ne vous servira qu’une fois ce point réglé.

Soyons honnêtes sur uses_transient_token : Google n’en donne pas de définition claire dans sa documentation. Il se rapporte aux jetons éphémères utilisés pour la modélisation en mode avancé. Dans la pratique, je ne l’utilise pas pour piloter : je m’appuie sur analytics_storage et ads_storage, qui suffisent largement à tout ce qui suit.

Basic ou Advanced : ce qui change tout dans l’export

Voici le point que la plupart des articles zappent, et c’est pourtant celui qui décide si vous pouvez mesurer quoi que ce soit. Le comportement de l’export dépend entièrement du mode de votre Consent Mode.

Consent Mode BasicConsent Mode Advanced
Un refus envoie-t-il un hit à GA4 ?Non, rien ne partOui, un ping cookieless
Ligne présente dans l’export BigQuery ?AucuneOui, analytics_storage = 'No'
user_pseudo_id sur un refusAbsent (aucune ligne)null
ga_session_id sur un refusAbsent (aucune ligne)null
Taux de refus mesurable dans BigQuery ?Non, refus invisiblesOui
Données modélisées dans l’export ?NonNon

En mode Basic, les tags sont bloqués tant que le consentement n’est pas accordé. Résultat : un visiteur qui refuse n’envoie strictement rien, et il n’existe aucune ligne pour lui dans BigQuery. Votre export ne contient que des consentants, donc analytics_storage vaut toujours "Yes". Conséquence directe et contre-intuitive : en mode Basic, vous ne pouvez pas calculer votre taux de refus depuis BigQuery, parce que les refus sont tout simplement absents des données.

En mode Advanced, c’est l’inverse. Les tags se chargent quand même et envoient un ping cookieless même sans consentement. Ces lignes existent dans l’export, avec analytics_storage = 'No', mais leurs identifiants sont vidés : user_pseudo_id et ga_session_id sont null. On peut donc les compter en événements, mais pas en utilisateurs ni en sessions, puisqu’il n’y a plus d’identifiant pour les regrouper.

D’où un diagnostic gratuit en trente secondes : si votre export ne contient aucune ligne analytics_storage = 'No', vous êtes soit en Basic, soit sans Consent Mode avancé, et vous avez un angle mort sur tous vos refus. Si ce socle n’est pas clair chez vous, reprenez-le d’abord avec Consent Mode v2 dans GA4, puis revenez ici. Et si l’export BigQuery n’est pas encore branché sur votre propriété, tout commence par exploiter l’export GA4 BigQuery.

Requête 1 : votre taux de consentement par jour, device et pays

On attaque le concret. Cette requête calcule le taux de consentement analytics en se basant sur les événements page_view, pour limiter le biais (un consentant génère beaucoup plus d’événements qu’un refus, donc compter tous les événements gonfle artificiellement le taux).

SELECT
  PARSE_DATE('%Y%m%d', event_date)                 AS jour,
  device.category                                  AS device,
  geo.country                                      AS pays,
  COUNTIF(privacy_info.analytics_storage = 'Yes')  AS vues_consenties,
  COUNTIF(privacy_info.analytics_storage = 'No')   AS vues_refusees,
  ROUND(
    SAFE_DIVIDE(
      COUNTIF(privacy_info.analytics_storage = 'Yes'),
      COUNTIF(privacy_info.analytics_storage IN ('Yes', 'No'))
    ) * 100, 1
  )                                                AS taux_consentement_pct
FROM `votre-projet.analytics_XXXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20261001' AND '20261010'
  AND event_name = 'page_view'
GROUP BY jour, device, pays
ORDER BY jour DESC, vues_consenties DESC;

Deux détails qui comptent. Le filtre _TABLE_SUFFIX n’est pas cosmétique : sans lui, BigQuery scanne toutes vos tables quotidiennes depuis le début, et la facture grimpe vite. Bornez toujours la plage de dates. Et SAFE_DIVIDE évite une division par zéro sur une journée sans donnée, au lieu de faire planter la requête.

Lisez le résultat par segment, jamais en moyenne globale. Un taux de 70 % sur desktop et de 45 % sur mobile, ce n’est pas un taux de 58 %, ce sont deux problèmes différents. Les écarts par pays et par device sont souvent là que se cachent les vrais sujets : un bandeau illisible sur petit écran, une traduction manquante, une position de bouton malheureuse.

Requête 2 : le volume invisible

Combien de trafic vous échappe réellement ? Cette requête compte les événements par état de consentement et mesure la part sans identifiant, c’est-à-dire les pings cookieless du mode avancé.

SELECT
  privacy_info.analytics_storage                   AS consentement,
  COUNT(*)                                          AS evenements,
  COUNTIF(user_pseudo_id IS NULL)                   AS sans_user_id,
  COUNTIF(
    (SELECT value.int_value FROM UNNEST(event_params)
     WHERE key = 'ga_session_id') IS NULL
  )                                                 AS sans_session_id
FROM `votre-projet.analytics_XXXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20261001' AND '20261010'
GROUP BY consentement
ORDER BY evenements DESC;

La ligne consentement = 'No' est votre population fantôme : des visiteurs bien réels, qui ont interagi, mais que vous ne pouvez ni identifier, ni suivre, ni attribuer. En mode avancé, c’est aussi la matière première que Google utilise pour modéliser vos conversions dans l’interface. Plus cette ligne est grosse, plus l’écart entre votre interface GA4 et votre BigQuery sera large, et plus vos décisions basées sur le seul rapport GA4 reposent sur du reconstruit.

Requête 3 : l’alerte bannière cassée

Le scénario qui fait mal : un déploiement de la CMP qui casse l’intégration, un tag qui cesse de pousser l’état de consentement, un changement de layout qui enterre le bouton d’acceptation. Votre taux de consentement s’effondre du jour au lendemain, et vous le découvrez trois semaines plus tard quand les conversions ont déjà chuté. Cette requête compare chaque jour à sa moyenne des 7 jours précédents pour sonner l’alarme tôt.

WITH quotidien AS (
  SELECT
    PARSE_DATE('%Y%m%d', event_date) AS jour,
    SAFE_DIVIDE(
      COUNTIF(privacy_info.analytics_storage = 'Yes'),
      COUNTIF(privacy_info.analytics_storage IN ('Yes', 'No'))
    ) AS taux
  FROM `votre-projet.analytics_XXXXXX.events_*`
  WHERE _TABLE_SUFFIX BETWEEN '20260911' AND '20261010'
    AND event_name = 'page_view'
  GROUP BY jour
)
SELECT
  jour,
  ROUND(taux * 100, 1) AS taux_pct,
  ROUND(AVG(taux) OVER (
    ORDER BY jour ROWS BETWEEN 7 PRECEDING AND 1 PRECEDING
  ) * 100, 1) AS moyenne_7j_pct,
  ROUND((taux - AVG(taux) OVER (
    ORDER BY jour ROWS BETWEEN 7 PRECEDING AND 1 PRECEDING
  )) * 100, 1) AS ecart_points
FROM quotidien
ORDER BY jour DESC;

Lisez la colonne ecart_points. Un écart de -2 ou -3 points, c’est du bruit normal. Un écart de -15 points d’un jour à l’autre, c’est une bannière cassée jusqu’à preuve du contraire, et votre signal de déclenchement d’alerte. Branchez cette requête sur une requête planifiée (scheduled query) et une notification, et vous passez de la découverte tardive à la détection en vingt-quatre heures.

Interpréter, et surtout décider

Les chiffres ne servent à rien si vous en restez là. Trois cas de figure, trois décisions.

Si votre taux de consentement est correct et stable, votre travail est de protéger la part consentie : vérifiez que le signal remonte proprement, surveillez la requête 3, et optimisez la qualité du matching côté serveur. Si votre taux est bas et que l’essentiel de votre trafic bascule en 'No', la vraie question n’est plus technique mais stratégique : votre finalité est-elle vraiment publicitaire, ou juste de la mesure d’audience ? Dans le second cas, une mesure exemptée de consentement peut vous rendre tout le volume perdu. Si enfin vous perdez tant de signal que GA4 ne vous apprend plus grand-chose, il est temps de regarder ailleurs : d’autres outils de mesure n’ont tout simplement pas ce problème de bannière.

Quelle que soit la direction, vous partez désormais d’un chiffre réel et pas d’une impression. Pour aller plus loin dans l’exploitation de l’export, j’ai rassemblé 10 requêtes BigQuery GA4 qui complètent celles-ci.

FAQ

Pourquoi mon user_pseudo_id est-il null pour certaines lignes ? Parce que vous êtes en Consent Mode avancé et que ces lignes sont des pings cookieless de visiteurs non consentants. GA4 collecte l’événement mais supprime les identifiants. C’est normal, et c’est précisément ce qui permet de les compter comme volume sans les suivre comme utilisateurs.

Puis-je filtrer les non-consentants avec where privacy_info.analytics_storage = 'Yes' ? Oui, mais sachez que vous introduisez un biais : le consentement varie selon le device, le pays et la page, donc votre échantillon consentant n’est pas représentatif de l’ensemble. C’est acceptable pour une analyse de comportement, pas pour un comptage de volume.

La modélisation de GA4 apparaît-elle dans BigQuery ? Non. La modélisation s’applique dans l’interface et dans l’API, jamais dans l’export BigQuery. C’est pour cela que vos totaux BigQuery sont souvent inférieurs à ceux de l’interface, et c’est aussi pour cela que BigQuery est la source la plus fiable pour mesurer le consentement brut.

Mon export ne contient aucune ligne 'No', est-ce un bug ? Non, c’est un symptôme. Vous êtes très probablement en Consent Mode basic (où les refus n’envoient rien) ou sans Consent Mode. Dans les deux cas, vos refus sont invisibles dans BigQuery, et vous ne pouvez pas mesurer votre taux de refus tant que vous n’êtes pas passé en mode avancé.

Comment limiter le coût de ces requêtes ? Bornez toujours _TABLE_SUFFIX sur la plage de dates utile. C’est le levier numéro un, car BigQuery facture les données scannées, et une requête sans borne lit l’intégralité de l’historique.

Mon avis de praticien

Si je dois résumer : arrêtez de piloter votre consentement depuis le tableau de bord de votre CMP. Ce chiffre est une mesure de clics sur un bandeau, pas une mesure de ce que votre analytics voit. La seule vérité qui compte pour vos décisions, c’est celle de l’export brut, parce que c’est elle qui conditionne ce que Google peut modéliser, ce que vos conversions valent, et ce que vous perdez vraiment. Passez en Consent Mode avancé si ce n’est pas déjà fait, ne serait-ce que pour rendre vos refus visibles et mesurables. Lancez la requête 1 une fois pour voir où vous en êtes, planifiez la requête 3 pour ne plus jamais découvrir une bannière cassée avec trois semaines de retard, et servez-vous de la requête 2 pour chiffrer, en euros de signal perdu, l’arbitrage qui vous attend. Le consentement est devenu un sujet de données avant d’être un sujet de conformité. Autant le traiter avec des données.