GA4 stocke la majeure partie de sa valeur analytique dans event_params — un champ RECORD répété contenant des paires clé-valeur pour chaque paramètre d’événement. L’extraction de ces paramètres en SQL nécessite une sous-requête corrélée pour chaque paramètre voulu. À grande échelle, écrire cela en ligne pour 20+ paramètres par modèle devient ingérable.
La solution est une macro dbt qui encapsule le pattern d’extraction.
La macro de base
-- macros/ga4/extract_event_param.sql
{% macro extract_event_param(params_column, param_key, value_type='string_value') %} ( SELECT value.{{ value_type }} FROM UNNEST({{ params_column }}) WHERE key = '{{ param_key }}' LIMIT 1 ){% endmacro %}Cela génère une sous-requête corrélée en ligne — l’approche qui extrait la valeur d’un paramètre sans développer les lignes. La garde LIMIT 1 gère le cas rare où un paramètre apparaît plusieurs fois dans event_params (un cas limite connu de GA4 pour certaines implémentations de tracking).
Utilisation dans un modèle de base :
{{ extract_event_param('event_params', 'page_location', 'string_value') }} AS page__location,{{ extract_event_param('event_params', 'ga_session_id', 'int_value') }} AS session__ga_id,{{ extract_event_param('event_params', 'session_engaged', 'string_value') }} AS session__is_engagedLe paramètre value_type correspond aux quatre champs possibles dans la structure de valeur de paramètre de GA4 :
string_value— paramètres texte (URL de page, catégories d’événement, dimensions personnalisées sous forme de chaîne)int_value— paramètres entiers (ga_session_id,ga_session_number,entrances)float_value— valeurs décimalesdouble_value— décimales haute précision (moins courant, utilisé pour certains champs de revenus)
Pourquoi une sous-requête corrélée, pas CROSS JOIN UNNEST
Deux approches existent pour extraire des éléments de tableaux dans BigQuery :
Sous-requête corrélée (utilisée dans cette macro) :
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location' LIMIT 1)CROSS JOIN UNNEST :
FROM eventsCROSS JOIN UNNEST(event_params) AS paramWHERE param.key = 'page_location'L’approche CROSS JOIN multiplie les lignes. Un événement avec 15 paramètres génère 15 lignes dans le résultat intermédiaire — 14 d’entre elles étant filtrées. Dans un modèle de base sélectionnant 20 paramètres, cela crée d’énormes ensembles de résultats intermédiaires que BigQuery doit trier.
La sous-requête corrélée conserve exactement une ligne par événement quel que soit le nombre de paramètres. Pour les données GA4 avec 10 à 30 paramètres par événement, c’est une différence significative en termes d’efficacité des requêtes.
L’optimiseur de requêtes de BigQuery peut également regrouper plusieurs sous-requêtes corrélées en un seul passage sur event_params — donc extraire 20 paramètres ne signifie pas 20 analyses séparées du tableau.
La variante numérique
GA4 présente une incohérence : certains paramètres qui sont conceptuellement numériques se retrouvent dans différents champs de valeur selon le contexte. Les revenus peuvent arriver en tant que float_value ou double_value. Les dimensions personnalisées passent parfois entre int_value et float_value. Une macro robuste gère les trois champs numériques :
{% macro extract_event_param_numeric(params_column, param_key) %} ( SELECT COALESCE( value.int_value, CAST(value.float_value AS INT64), CAST(value.double_value AS INT64) ) FROM UNNEST({{ params_column }}) WHERE key = '{{ param_key }}' LIMIT 1 ){% endmacro %}Utilisez extract_event_param_numeric pour les paramètres dont vous n’êtes pas certain du champ numérique que GA4 va renseigner. Utilisez extract_event_param avec un value_type explicite lorsque vous savez exactement ce que le paramètre stocke.
Le piège int_value pour les ID de session
ga_session_id est stocké dans value.int_value. Une erreur courante est de l’extraire comme string_value :
-- INCORRECT : Retourne NULL pour ga_session_id{{ extract_event_param('event_params', 'ga_session_id', 'string_value') }}
-- CORRECT : Retourne l'identifiant de session entier{{ extract_event_param('event_params', 'ga_session_id', 'int_value') }}Les ID de session nuls se propagent en cascades dans une construction de clé de session défaillante, qui brise toutes les fonctions de fenêtrage partitionnées par session_key en aval. Vérifiez toujours quel champ de valeur un paramètre utilise d’après la référence du schéma GA4.
Extraction pilotée par variables pour les paramètres personnalisés
Pour les projets avec de nombreux paramètres d’événements personnalisés, l’approche d’extraction pilotée par variables s’adapte mieux que le codage en dur de chaque paramètre. Une boucle sur une liste configurée :
vars: ga4: custom_parameters: - name: "user_type" value_type: "string_value" - name: "experiment_id" value_type: "string_value" - name: "product_category" value_type: "string_value"{% for param in var('ga4:custom_parameters', []) %} {{ extract_event_param('event_params', param.name, param.value_type) }} AS custom__{{ param.name }},{% endfor %}Cela transforme l’ajout de nouveaux paramètres personnalisés en un changement de configuration plutôt que de SQL — utile pour les propriétés qui font évoluer leur tracking au fil du temps.
Organisation des macros
Conservez les macros spécifiques à GA4 dans leur propre sous-dossier :
macros/└── ga4/ ├── extract_event_param.sql ├── extract_event_param_numeric.sql └── default_channel_grouping.sqlLe sous-dossier clarifie le namespace des macros : {{ extract_event_param() }} est manifestement une macro du domaine GA4. Pour une réutilisation inter-projets, ces macros pourraient résider dans un package dbt privé — surtout si vous gérez plusieurs propriétés GA4 sur des projets clients.