ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Structure des données d'événements GA4

Comment GA4 structure les données d'événements dans BigQuery — le modèle événementiel, les paramètres imbriqués, et les patterns nécessaires pour l'interroger efficacement.

Planté
ga4bigqueryanalyticsdata modeling

GA4 est architecturalement différent de Universal Analytics. UA vous donnait les sessions comme unité d’analyse — une ligne par session avec des événements imbriqués à l’intérieur. GA4 inverse cela : tout est un événement, et les sessions sont quelque chose que vous construisez ensuite à partir des données au niveau événement.

Le modèle centré sur les événements

Lorsque les données GA4 arrivent dans BigQuery, la table events_YYYYMMDD a une ligne par événement — chaque clic, défilement, page vue et achat se déclenche comme une ligne distincte. Il n’y a pas de métriques de session pré-agrégées ni de hiérarchie. Les définitions de session, les calculs d’engagement et les tables de sessions doivent être construits dans la couche de transformation à partir des données d’événements brutes.

Structures imbriquées : la réalité du schéma

GA4 n’aplatit pas tout en colonnes. Il utilise des champs RECORD imbriqués et des tableaux repeated pour garder les données liées ensemble et éviter l’explosion du schéma. Le schéma de premier niveau semble propre :

event_name
event_timestamp
event_date
user_pseudo_id
user_id

Mais les données réelles vivent plus profondément. La plupart de votre valeur analytique réside dans deux champs repeated :

event_params est un tableau de paires clé-valeur où GA4 stocke les données de paramètres : page_location, page_title, ga_session_id, les dimensions personnalisées, les métriques d’engagement — essentiellement tout ce qui n’est pas un champ de premier niveau. Chaque élément a une key (le nom du paramètre) et un RECORD value avec quatre champs possibles : string_value, int_value, float_value et double_value. GA4 détecte automatiquement quel champ est renseigné en fonction de votre type de données.

user_properties reproduit cette structure mais à la portée utilisateur — propriétés que vous définissez via setUserProperty qui persistent entre les sessions. Contrairement aux paramètres d’événements, les user properties incluent un set_timestamp_micros pour tracker quand elles ont été mises à jour pour la dernière fois.

items (pour l’e-commerce) est un RECORD repeated séparé. Chaque produit dans un achat génère un élément avec item_id, item_name, price, quantity et optionnellement item_params (un champ repeated imbriqué pour les dimensions produit personnalisées ajouté en octobre 2023).

Les données de device, géographie et source de trafic sont des RECORDs imbriqués — valeurs uniques par événement mais structurées hiérarchiquement. device.category vous indique desktop/mobile/tablette. geo.country vous indique la localisation de l’utilisateur. traffic_source, collected_traffic_source et session_traffic_source_last_click fournissent chacun des vues différentes de l’attribution.

Pourquoi cette structure existe

L’imbrication n’est pas accidentelle. GA4 hérite son schéma d’export de Firebase, et la conception privilégie les données éparses. Tous les événements n’ont pas tous les paramètres. Si GA4 aplatissait tous les paramètres possibles en colonnes séparées, vous auriez des milliers de colonnes avec 99 % de NULLs. Les tableaux imbriqués maintiennent le schéma gérable et permettent de n’interroger que ce dont vous avez besoin.

L’inconvénient est que la plupart des requêtes analytiques nécessitent des patterns UNNEST. Vous ne pouvez pas écrire SELECT page_location. Vous écrivez :

SELECT
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location') AS page_location
FROM events_*

C’est le coût du modèle événementiel. Mais une fois les patterns internalisés, cela devient mécanique.

Les deux approches UNNEST

Les sous-requêtes corrélées (le pattern ci-dessus) extraient des paramètres spécifiques sans développer les lignes. Un événement avec 20 paramètres produit toujours une ligne en sortie. La sous-requête plonge dans le tableau, trouve la clé souhaitée et retourne la valeur. Utilisez ce pattern pour la plupart des requêtes.

UNNEST en clause FROM développe les tableaux en lignes séparées — une ligne par élément. C’est utile pour la découverte, l’audit des paramètres, ou lorsque vous devez vraiment analyser la structure du tableau elle-même. Mais cela crée une explosion de lignes : 15 paramètres deviennent 15 lignes par événement.

Le modèle mental : utilisez des sous-requêtes corrélées lorsque vous savez quel paramètre vous voulez. Utilisez UNNEST en clause FROM lorsque vous explorez ou avez besoin de travailler sur les éléments du tableau.

Identité de session : le problème de la clé composite

Le paramètre ga_session_id réside dans event_params.int_value. C’est le timestamp Unix du démarrage de la session — un identifiant pratique car il est présent sur chaque événement et lié à la définition de session de GA4.

Mais voici le piège : ga_session_id n’est pas globalement unique. Plusieurs utilisateurs démarrant des sessions à la même seconde partagent des valeurs identiques. Si vous utilisez ga_session_id seul pour dédupliquer, vous fusionnerez accidentellement des événements de différents utilisateurs dans la même « session ».

La correction est mécanique mais critique : combinez user_pseudo_id + ga_session_id en une clé de session composite.

CONCAT(user_pseudo_id, '.', CAST(
(SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id')
AS STRING
)) AS session_key

Cette clé composite apparaît dans toute la logique de construction de sessions — les clauses PARTITION BY des fonctions fenêtre, les agrégations au niveau session, et toute analyse qui dépend du regroupement des événements en sessions cohérentes.

Différences avec Universal Analytics

UAGA4
Grain de la ligneUne ligne par sessionUne ligne par événement
IDs de sessionChamps directsExtraits des tableaux event_params
MétriquesPré-calculées (totals.pageviews, totals.bounces)Calculées au moment de la requête ou dans la couche de transformation
Dimensions personnaliséesSlots indexés (dimension1, dimension2)Paires clé-valeur dans event_params

La différence structurelle affecte où se produit le calcul des métriques : UA exposait des métriques pré-construites ; GA4 expose des événements bruts et délègue l’agrégation à la requête ou à la couche de transformation.

Quand matérialiser vs interroger en direct

Pour l’exploration ad-hoc, les sous-requêtes corrélées conviennent. Pour le reporting de production, la matérialisation est préférable : les paramètres sont extraits une seule fois et stockés dans une table d’événements enrichie avec le contexte de session déjà attaché. Chaque requête en aval s’exécute sur des données aplaties.

Le pattern standard : événements bruts → table intermédiaire d’événements sessionisés (paramètres extraits, contexte de session ajouté via fonctions fenêtre) → marts finaux pour les tableaux de bord et le reporting. La complexité UNNEST est concentrée en un seul endroit ; les modèles en aval héritent de colonnes plates et typées.

Champs de source de trafic : trois structures différentes

GA4 fournit trois RECORDs de source de trafic, chacun servant un objectif différent. Comprendre lequel utiliser évite les erreurs d’attribution :

  • traffic_source : Niveau utilisateur, attribution premier contact. La source qui a initialement acquis l’utilisateur. Jamais dans les tables intraday.
  • collected_traffic_source : Données de collecte brutes au niveau événement avec paramètres UTM et click IDs. Utile pour la modélisation d’attribution personnalisée.
  • session_traffic_source_last_click (depuis juillet 2024) : Attribution au niveau session avec le modèle dernier clic non-direct de GA4 appliqué. Correspond à l’interface GA4.

Pour les données depuis juillet 2024, session_traffic_source_last_click est le champ recommandé pour l’attribution de session. Les données plus anciennes nécessitent de construire l’attribution de session depuis collected_traffic_source ou traffic_source.

Exemple d’extraction pratique

Le pattern pour extraire plusieurs paramètres tout en conservant une ligne par événement :

SELECT
event_name,
event_timestamp,
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location') AS page_location,
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_title') AS page_title,
(SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS session_id,
user_pseudo_id,
device.category,
geo.country
FROM `project.analytics_PROPERTY_ID.events_*`
WHERE _TABLE_SUFFIX = '20260326'

Chaque extraction de paramètre est indépendante — la sous-requête plonge dans le tableau pour une clé spécifique et retourne une valeur. Ce pattern scanne le tableau event_params plusieurs fois par événement, mais l’optimiseur de requêtes imbriquées de BigQuery peut regrouper plusieurs sous-requêtes corrélées en un seul passage.

Associé

  • GA4 BigQuery Export : Complete Schema Reference — Chaque champ expliqué, pièges critiques, évolution du schéma
  • Unnesting GA4 Events : Patterns for Every Use Case — Patterns SQL production-ready, templates dbt, optimisation des performances
  • Building Session Tables from GA4 Event Data — Comment ajouter le contexte de session aux événements via les fonctions fenêtre