Consultar datos de GA4 con BigQuery sin volverse loco

En el ecosistema actual del marketing digital, los datos han dejado de ser un simple accesorio para convertirse en el motor principal de la estrategia. Sin embargo, muchos profesionales se encuentran con una barrera invisible: los informes estándar de la interfaz de Google Analytics 4 (GA4)

Aunque útiles para una visión rápida, estos informes suelen estar limitados por el muestreo, los umbrales de datos y una estructura rígida que no siempre responde a las preguntas más complejas del negocio.

Es aquí donde la exportación nativa a BigQuery transforma las reglas del juego.

Estructura de las tablas de GA4 en BigQuery

Una vez configurada la exportación, GA4 crea automáticamente tablas en BigQuery con una estructura específica que es tenéis que entender, porque no es una tabla particionada clásica. En este artículo, no entraré en el caso especial de los datos en streaming, asumiré que usáis la exportación diaria. 

Nomenclatura de las tablas

Las tablas de GA4 en BigQuery siguen este patrón:

`<id_proyecto_gcp>.analytics_<id_analytics>.events_YYYYMMDD`

Donde:

  • <id_proyecto_gcp>: Es el ID de vuestro proyecto GCP
  • <id_analytics>: Es un dataset que se crea automáticamente con el ID numérico de vuestra propiedad GA4
  • events_YYYYMMDD: Cada día se crea una nueva tabla con el formato de fecha (año, mes, día)

Estructura de datos: modelo basado en eventos

Columnas principales de la tabla events_

Las columnas más importantes que encontraréis en las tablas de eventos son:

ColumnaTipoDescripción
event_dateSTRINGFecha del evento en formato YYYYMMDD
event_timestampINTEGERTimestamp en microsegundos desde el 1 de enero de 1970
event_nameSTRINGNombre del evento (page_view, purchase, etc.)
event_paramsRECORDArray de parámetros del evento
event_previous_timestampINTEGERTimestamp del evento anterior del mismo usuario
event_value_in_usdFLOATValor del evento en USD (si aplica)
event_bundle_sequence_idINTEGERID de secuencia del bundle de eventos
event_server_timestamp_offsetINTEGEROffset del timestamp del servidor
user_idSTRINGID del usuario (si está configurado)
user_pseudo_idSTRINGID pseudo-anónimo del usuario (client_id)
privacy_infoRECORDInformación sobre el consentimiento y privacidad
user_propertiesRECORDPropiedades del usuario
user_first_touch_timestampINTEGERTimestamp del primer contacto del usuario
user_ltvRECORDValor de vida del usuario
deviceRECORDInformación del dispositivo
geoRECORDInformación geográfica
app_infoRECORDInformación de la aplicación
collected_traffic_sourceRECORDFuente de tráfico recopilada en el evento actual
session_traffic_source_last_clicksRECORDÚltima fuente de tráfico con clic de la sesión
traffic_sourceRECORDInformación de la fuente de tráfico
stream_idSTRINGID del flujo de datos
platformSTRINGPlataforma (WEB, IOS, ANDROID)
event_dimensionsRECORDDimensiones del evento
ecommerceRECORDInformación de e-commerce
itemsRECORD Array de items (para eventos de e-commerce)

Para más información sobre estos campos y subcampos, mirad la documentación.

Estructura de datos anidados (nested data)

Una característica importante de las tablas de GA4 es el uso extensivo de datos anidados (nested data en inglés). Esto significa que algunas columnas contienen estructuras complejas dentro de ellas. Por ejemplo, event_params es un array de registros que contiene:

  • key: El nombre del parámetro
  • value: El valor del parámetro (que puede ser string, int, float, o double)

Este formato poco habitual existe porque los parámetros de los eventos en Google Analytics dependen del evento. Para una página vista, el código enviará un payload similar al que indico a continuación: 

{
  "event_date": "20250115",
  "event_timestamp": 1705324800000000,
  "event_name": "page_view",
  "event_params": [
    {
      "key": "page_location",
      "value": "https://www.ejemplo.com/productos/categoria-1"
    },
    {
      "key": "page_title",
      "value": "Categoría de Productos - Mi Tienda"
    },
    {
      "key": "page_referrer",
      "value": "https://www.google.com/search?q=productos"
    },
    {
      "key": "ga_session_id",
      "value": 1705324800
    },
    {
      "key": "entrances",
      "value": 1
    },
    {
      "key": "engagement_time_msec",
      "value": 5000
    }
  ],
  "user_pseudo_id": "1234567890.1234567890",
  "device": {
    "category": "desktop",
    "operating_system": "Windows",
    "browser": "Chrome"
  },
  "geo": {
    "country": "Spain",
    "city": "Madrid"
  }
}

Pero para un evento de registro, tendremos lo siguiente:

{
  "event_date": "20250115",
  "event_timestamp": 1705324800000000,
  "event_name": "sign_up",
  "event_params": [
    {
      "key": "page_location",
      "value": "https://www.ejemplo.com/registro"
    },
    {
      "key": "method",
      "value": "Google"
    }
  ],
  "user_pseudo_id": "1234567890.1234567890",
  "device": {
    "category": "desktop",
    "operating_system": "Windows",
    "browser": "Chrome"
  },
  "geo": {
    "country": "Spain",
    "city": "Madrid"
  }
}

Como véis, lo que tenemos dentro de event_params depende del evento, y es la gran diferencia entre GA4 y la versión anterior: FLEXIBILIDAD. Para conservar esta ventaja en BigQuery, Google ha tenido que usar una estructura en sus tablas que permite recibir información diferente en una única columna. En efecto, no podemos tener un sistema que crea una columna nueva cada vez que detecta un parámetro diferente, sería inviable y poco eficiente.  

Por eso, tenemos este formato poco habitual y que nos da algunos dolores de cabeza en SQL. Para trabajar con estos datos anidados, necesitaréis usar funciones específicas de BigQuery como UNNEST.

Consultas básicas

Si no necesitamos usar los datos de las columnas que requieren el uso de UNNEST, podemos usar SQL clásico cómo siempre lo hemos hecho. 

Consultar eventos de un día específico

La forma más básica de consultar datos de GA4 es seleccionar eventos de una fecha concreta:

SELECT 
  event_name,
  COUNT(*) as event_count
FROM `xxxxxxx.analytics_397818756.events_20250115`
GROUP BY event_name
ORDER BY event_count DESC

Consultar múltiples días usando wildcards

Para consultar datos de varios días, podéis usar el carácter comodín estrella (*) en el nombre de la tabla:

SELECT 
event_name, 
COUNT(*) as event_count
FROM `xxxxxxx.analytics_397818756.events_202501*` 
GROUP BY event_name 
ORDER BY event_count DESC

Esta consulta procesa todas las tables de enero del 2025 (todas las tablas que empiezan por event_202501). 

Cuando usáis wildcards que incluyen muchos días y dónde no podemos usar un wildcard, siempre debéis filtrar por `_TABLE_SUFFIX` para limitar las tablas que se escanean y reducir costes. Es parecido al sistema de optimización que se usa para las particiones. 

SELECT 
event_date, 
event_name, 
COUNT(*) as event_count 
FROM `xxxxxxx.analytics_397818756.events_*` 
WHERE _TABLE_SUFFIX BETWEEN '20250101' AND '20250231' 
GROUP BY event_date, event_name 

Consultar eventos más recientes

Para obtener los datos más recientes disponibles, podéis usar una subconsulta para encontrar la fecha máxima:

DECLARE max_date STRING;
SET max_date = (
  SELECT MAX(_TABLE_SUFFIX) 
  FROM `xxxxxxx.analytics_397818756.events_*`
);

SELECT 
  event_name,
  COUNT(*) as event_count
FROM `xxxxxxx.analytics_397818756.events_*`
WHERE _TABLE_SUFFIX = max_date
GROUP BY event_name
ORDER BY event_count DESC

Con este código, vamos a ejecutar dos consultas diferentes: 

1. Una para obtener la fecha máxima 

2. Otra para ejecutar el resto del código SQL 

Si usamos una subconsulta clásica, el coste sería más elevado porque BigQuery seleccionaría todos los datos y después filtraría en base al resultado de la subconsulta. 

SELECT 
  event_name,
  COUNT(*) as event_count
FROM `xxxxxxx.analytics_397818756.events_*`
WHERE _TABLE_SUFFIX = (SELECT MAX(_TABLE_SUFFIX) FROM `xxxxxxx.analytics_397818756.events_*`)
GROUP BY event_name
ORDER BY event_count DESC

Trabajar con parámetros de eventos

Los parámetros de eventos son una de las partes más importantes y complejas de trabajar con datos de GA4 en BigQuery. Cada evento puede tener múltiples parámetros personalizados.

Extraer un parámetro específico

Para extraer un parámetro específico, podéis usar una subconsulta. Lo único que tenéis que mirar antes es si el dato se encuentra en la columnas value.string_value, value.int_value, value.float_value o value.double_value

El código que vais a generar para extraer los valores de cada uno de vuestros parámetros se parece a un subconsulta: 

(SELECT value.string_value 
   FROM UNNEST(event_params) 
   WHERE key = 'page_location') as page_location,

En una consulta completa, tendríais, por ejemplo:

SELECT 
  event_name,
  (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
FROM `xxxxxxx.analytics_397818756.events_*`
WHERE _TABLE_SUFFIX = '20250115'
AND event_name = 'page_view'
LIMIT 100

Si usamos el nombre de un parámetro que no existe, el valor devuelto siempre será NULL y no tendremos ningún error, así que comprobad bien que estáis usando los nombres correctos. 

Simplificar la extracción de parámetros

Para hacer vuestras consultas más legibles, podéis crear una CTE para hacer la extracción inicial de los datos que necesitáis, para después seguir con la consulta que os permite contestar a vuestra pregunta. Por ejemplo:

WITH events_with_params AS (
  SELECT 
    event_timestamp,
    event_name,
    user_pseudo_id,
    (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
  FROM `xxxxxxx.analytics_397818756.events_*`
  WHERE _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
    AND event_name = 'page_view'
)
SELECT 
  page_location,
  COUNT(*) as page_views
FROM events_with_params
GROUP BY page_location
ORDER BY page_views DESC
LIMIT 10

Enfoque para consultar datos de GA4 

Como conclusión, os invito a seguir este proceso para crear vuestras consultas rápidamente. 

ETAPA 1: Listar todos las columnas y parámetros que vamos a necesitar. Podéis usar cualquier sistema de IA enchufando la URL de la documentación para ir más rápido. Como consejo, os agrego agregar este artículo en el contexto de la IA, así tendrá más información sobre los datos de GA4 y os devolverá mejores resultados 🙂 

ETAPA 2: Hacer lo mismo con los parámetros.

ETAPA 3: Seguir con el análisis. Véis, no es tan complicado al final. 

Antoine Eripret
Antoine Eripret

SEO desde 2016, trabajo en la intersección entre SEO, ingeniería de datos y automatización. Me gusta sobre todo Airflow, SQL (BigQuery), DBT/Dataform y Python.

Deja un comentario