Au-delà de l’e-commerce, GA4 tracke des dizaines d’événements d’engagement via ses fonctionnalités de mesure améliorée. Chaque type d’événement stocke ses données dans différentes clés event_params, et les extraire suit le même pattern de sous-requête corrélée — mais connaître quels paramètres extraire pour chaque type d’événement fait gagner un temps de découverte considérable.
Ce sont des recettes prêtes à copier-coller. Adaptez la plage _TABLE_SUFFIX et les références de projet à votre configuration.
Pages vues avec parsing propre des URLs
L’événement page_view est l’événement GA4 le plus couramment interrogé. Les paramètres utiles se trouvent dans event_params, pas comme champs de premier niveau :
SELECT PARSE_DATE('%Y%m%d', event_date) AS event_date, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location') AS page_url, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_title') AS page_title, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_referrer') AS referrer, -- Extraire le chemin propre sans protocole ni paramètres de requête REGEXP_REPLACE( REGEXP_REPLACE( (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location'), r'^https?://[^/]+', '' ), r'[\?#].*$', '' ) AS page_path, -- Identifier les pages d'entrée IFNULL( (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'entrances'), 0 ) = 1 AS is_landing_pageFROM `project.dataset.events_*`WHERE event_name = 'page_view' AND _TABLE_SUFFIX BETWEEN '20240101' AND '20240131'Le double REGEXP_REPLACE pour page_path est un pattern que vous réutiliserez dans chaque requête au niveau page. Le premier passage supprime le protocole et le domaine (https://example.com/products devient /products). Le second supprime les paramètres de requête et les fragments. Si vous construisez cela dans dbt, mettez l’extraction du chemin dans une macro réutilisable.
Le paramètre entrances identifie les pages d’entrée — la première page vue dans une session. C’est un int_value, pas une chaîne, donc extrayez-le en conséquence.
Analyse de la profondeur de défilement
La mesure améliorée de GA4 déclenche un événement scroll lorsque les utilisateurs atteignent 90 % de profondeur de défilement sur une page (ce seuil n’est pas configurable). L’événement lui-même est simple — l’analyse intéressante vient du calcul du taux de défilement par rapport aux pages vues :
WITH page_views AS ( SELECT REGEXP_REPLACE( REGEXP_REPLACE( (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location'), r'^https?://[^/]+', '' ), r'[\?#].*$', '' ) AS page_path, COUNT(*) AS pageviews FROM `project.dataset.events_*` WHERE event_name = 'page_view' AND _TABLE_SUFFIX BETWEEN '20240101' AND '20240131' GROUP BY page_path),
scrolls AS ( SELECT REGEXP_REPLACE( REGEXP_REPLACE( (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location'), r'^https?://[^/]+', '' ), r'[\?#].*$', '' ) AS page_path, COUNT(*) AS scroll_events FROM `project.dataset.events_*` WHERE event_name = 'scroll' AND _TABLE_SUFFIX BETWEEN '20240101' AND '20240131' GROUP BY page_path)
SELECT pv.page_path, pv.pageviews, IFNULL(s.scroll_events, 0) AS scroll_events, SAFE_DIVIDE(s.scroll_events, pv.pageviews) AS scroll_rateFROM page_views pvLEFT JOIN scrolls s ON pv.page_path = s.page_pathWHERE pv.pageviews > 100ORDER BY scroll_rate DESCLe filtre HAVING pageviews > 100 élimine les pages à faible trafic où le taux de défilement est bruité. Ajustez le seuil selon votre volume de trafic.
Un taux de défilement faible sur un article long peut indiquer un faible engagement après le premier écran. Un taux de défilement élevé sur une page courte est attendu. Le taux de défilement est le plus significatif lorsqu’on le compare entre types de pages similaires.
Tracking des clics et des liens sortants
L’événement click se déclenche pour les liens sortants (lorsque la mesure améliorée est activée). Les paramètres clés :
SELECT (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'link_url') AS link_url, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'link_domain') AS link_domain, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'outbound') AS is_outbound, COUNT(*) AS clicksFROM `project.dataset.events_*`WHERE event_name = 'click' AND _TABLE_SUFFIX BETWEEN '20240101' AND '20240131'GROUP BY link_url, link_domain, is_outboundORDER BY clicks DESCLe paramètre outbound est une chaîne 'true' ou 'false', pas un booléen — la détection de type le stocke comme string_value. Filtrez avec = 'true' si vous voulez uniquement les clics externes.
Tracking des téléchargements de fichiers
GA4 tracke automatiquement les téléchargements de types de fichiers courants (pdf, xlsx, docx, csv, etc.) lorsque la mesure améliorée est activée :
SELECT (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'file_name') AS file_name, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'file_extension') AS file_extension, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'link_url') AS download_url, COUNT(*) AS downloads, COUNT(DISTINCT user_pseudo_id) AS unique_usersFROM `project.dataset.events_*`WHERE event_name = 'file_download' AND _TABLE_SUFFIX BETWEEN '20240101' AND '20240131'GROUP BY file_name, file_extension, download_urlORDER BY downloads DESCfile_name et file_extension sont extraits de l’URL par le JavaScript de GA4 — ils peuvent être incorrects si l’URL ne contient pas un pattern de nom de fichier traditionnel. Vérifiez toujours contre link_url pour la précision.
Funnel d’engagement vidéo
GA4 tracke automatiquement les vidéos YouTube embarquées (lorsque la mesure améliorée est activée) via trois événements : video_start, video_progress et video_complete. L’événement video_progress se déclenche aux jalons 10 %, 25 %, 50 % et 75 %.
SELECT (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'video_title') AS video_title, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'video_provider') AS video_provider, COUNTIF(event_name = 'video_start') AS starts, COUNTIF(event_name = 'video_progress' AND (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'video_percent') = 25 ) AS reached_25_pct, COUNTIF(event_name = 'video_progress' AND (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'video_percent') = 50 ) AS reached_50_pct, COUNTIF(event_name = 'video_progress' AND (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'video_percent') = 75 ) AS reached_75_pct, COUNTIF(event_name = 'video_complete') AS completions, SAFE_DIVIDE( COUNTIF(event_name = 'video_complete'), COUNTIF(event_name = 'video_start') ) AS completion_rateFROM `project.dataset.events_*`WHERE event_name IN ('video_start', 'video_progress', 'video_complete') AND _TABLE_SUFFIX BETWEEN '20240101' AND '20240131'GROUP BY video_title, video_providerHAVING starts > 10ORDER BY starts DESCLe COUNTIF imbriqué avec une sous-requête corrélée à l’intérieur mérite étude. Il combine le filtrage au niveau événement (event_name = 'video_progress') avec le filtrage au niveau paramètre (video_percent = 50) en un seul passage d’agrégation. Ce pattern fonctionne pour toute analyse de funnel où vous devez compter des événements qui correspondent à la fois à un type d’événement et à une valeur de paramètre spécifique.
Le filtre HAVING starts > 10 supprime les vidéos à faible trafic où les pourcentages du funnel sont statistiquement peu fiables. Les taux de complétion vidéo varient selon le type de contenu — 30 à 40 % est typique pour les vidéos marketing ; le contenu pédagogique atteint souvent 60 % ou plus.
Métriques de session
L’agrégation au niveau session nécessite la clé de session composite — user_pseudo_id combiné avec ga_session_id :
WITH session_events AS ( SELECT CONCAT( user_pseudo_id, '-', (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') ) AS session_id, user_pseudo_id, event_timestamp, event_name, (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'engagement_time_msec') AS engagement_time_msec, (SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'session_engaged') AS session_engaged, traffic_source.source, traffic_source.medium, device.category AS device_category, geo.country FROM `project.dataset.events_*` WHERE _TABLE_SUFFIX BETWEEN '20240101' AND '20240131')
SELECT session_id, user_pseudo_id, MIN(TIMESTAMP_MICROS(event_timestamp)) AS session_start, MAX(TIMESTAMP_MICROS(event_timestamp)) AS session_end, TIMESTAMP_DIFF( MAX(TIMESTAMP_MICROS(event_timestamp)), MIN(TIMESTAMP_MICROS(event_timestamp)), SECOND ) AS session_duration_seconds, COUNT(*) AS session_events, COUNTIF(event_name = 'page_view') AS session_pageviews, SUM(engagement_time_msec) / 1000 AS session_engagement_seconds, MAX(session_engaged) = '1' AS session_is_engaged, ANY_VALUE(source) AS source, ANY_VALUE(medium) AS medium, ANY_VALUE(device_category) AS device_category, ANY_VALUE(country) AS countryFROM session_eventsGROUP BY session_id, user_pseudo_idNotez que session_engaged est une chaîne '1', pas un entier — encore un piège de détection de type. Et engagement_time_msec est cumulatif entre les événements d’une session, donc SUM donne le temps d’engagement total.
Pour un usage en production, ce pattern appartient à un modèle dbt plutôt qu’à du SQL ad-hoc. Consultez l’architecture en trois couches pour voir comment cela s’intègre dans un pipeline complet.