Tutorial · BigQuery · 18 min

    BigQuery GA4 Export — From Linking to First Query

    Link GA4 to BigQuery, understand the events_* table schema, and run your first cohort query.

    1. Step 01

      Link GA4 to BigQuery

      Admin → BigQuery Links. Pick daily + streaming. Streaming costs basically nothing at most B2B scales and saves you a debugging headache later.

    2. Step 02

      Understand events_*

      Each row is one event. event_params is a repeated record — you'll UNNEST it constantly. user_properties is structured the same way.

    3. Step 03

      Your first cohort query

      SELECT DATE(TIMESTAMP_MICROS(event_timestamp)) AS d,
             COUNT(DISTINCT user_pseudo_id) AS users
      FROM `project.dataset.events_*`
      WHERE event_name = 'session_start'
        AND _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
      GROUP BY d ORDER BY d;
    4. Step 04

      Extracting an event param

      SELECT
        event_date,
        (SELECT value.string_value FROM UNNEST(event_params)
         WHERE key = 'page_location') AS page_location,
        COUNT(*) AS views
      FROM `project.dataset.events_*`
      WHERE event_name = 'page_view'
      GROUP BY 1, 2;
    5. Step 05

      Funnel with SQL (instead of GA4's UI)

      WITH steps AS (
        SELECT user_pseudo_id,
          MAX(IF(event_name = 'sign_up', 1, 0)) AS s1,
          MAX(IF(event_name = 'wallet_funded', 1, 0)) AS s2,
          MAX(IF(event_name = 'p2p_send_completed', 1, 0)) AS s3
        FROM `project.dataset.events_*`
        WHERE _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
        GROUP BY user_pseudo_id
      )
      SELECT SUM(s1) AS signed_up,
             SUM(s2) AS funded,
             SUM(s3) AS sent
      FROM steps;
    6. Step 06

      Cost control

      Always filter by _TABLE_SUFFIX — wildcard scans of events_* cost real money. Materialize daily aggregates into a separate table for dashboards.