← Todos los casos
Portfolio técnico de Analytics EngineeringProyecto propio de portfolio

Modelo dimensional de GA4 en BigQuery con dbt

dbt / BigQuery
Problema

El export nativo de GA4 a BigQuery no es una tabla analítica, es un log de eventos anidado: cada consulta repite el mismo UNNEST y arrastra el riesgo de contar compras duplicadas.

Diagnóstico

Sobre el dataset público de la Google Merchandise Store (4,3M eventos): la sesión no es una columna, purchase se duplica, y la atribución llega en dos ámbitos que no se pueden colapsar sin perder información.

Intervención

Cuatro modelos dbt en dos capas: staging aplana y tipa el evento; los marts exponen sesiones, compras deduplicadas y usuarios. 25 tests de calidad y CI en GitHub Actions.

Resultado

360.129 sesiones y 270.154 usuarios modelados, 4.451 compras deduplicadas, 25/25 tests en verde en local y en CI, documentación con lineage graph navegable publicada en GitHub Pages.

Contexto

Este proyecto no nace de un cliente. Nace de la necesidad de demostrar algo que un CV no demuestra por sí solo: que no solo se consultar GA4 en BigQuery, se sabe modelarlo. El dataset es deliberadamente público (la muestra ofuscada de la Google Merchandise Store que usa la propia documentación de Google), para que cualquier reclutador técnico pueda reproducir el proyecto exacto y comparar resultados.

Cómo se resolvió, en detalle

Por qué la sesión necesita una clave propia

ga_session_id vive dentro de event_params y se reinicia por usuario: dos usuarios distintos pueden tener el mismo ga_session_id sin que sea la misma sesión. session_key se construye concatenando user_pseudo_id y ga_session_id, dando una clave única y estable que es, de hecho, el grano de sesión nativo de GA4, solo que expuesto explícitamente en vez de dejarlo implícito en cada consulta.

Deduplicar purchase sin perder la primera transacción real

GA4 reenvía el evento purchase si el usuario recarga la página de confirmación. Sin controlarlo, total_revenue y AOV salen inflados. La solución es un qualify row_number() over (partition by transaction_id order by purchased_at) = 1, que conserva la primera ocurrencia por timestamp y descarta duplicados y transaction_id nulos o "(not set)".

Por qué el dataset se creó en US y no en Europa

El dataset público de GA4 vive en la región US, y BigQuery no permite JOINs entre regiones distintas. Crear el dataset destino en europe-west (el reflejo automático para un analista en la UE) habría hecho el proyecto irrealizable sin duplicar los datos primero. Decisión consciente y documentada, no un descuido.

Lo que esto revela

Modelar datos de producto reales, aunque sean de un dataset público y no de un cliente propio, obliga a tomar las mismas decisiones que un analytics engineer toma en el día a día: cómo definir sesión, cómo deduplicar, dónde vive el dato y por qué. Consultar GA4 en BigQuery y modelarlo son habilidades distintas, y solo la segunda se demuestra con un repo, tests y CI, no con una captura de un dashboard.

Preguntas frecuentes

¿Son datos reales de un cliente?

No, es el dataset público de muestra de GA4 de la Google Merchandise Store que usa la propia documentación de Google, ofuscado y abierto a cualquiera. Se dice explícitamente para evitar cualquier malentendido: el valor del proyecto está en el modelado, no en el origen del dato.

¿Por qué dbt y no solo SQL directo en BigQuery?

dbt aporta lo que SQL suelto no da: control de versiones del modelo, tests automáticos de calidad (25 en este proyecto), documentación y lineage generados automáticamente, y un pipeline de CI que valida cada cambio antes de fusionarlo. Es la diferencia entre una consulta puntual y un modelo de datos mantenible.

¿Tienes un problema parecido?

Pedir auditoría gratuita