The first time you open the GA4 export in BigQuery, it looks nothing like a report and everything like a puzzle: one row per event, with data folded inside data. Understanding that shape is the whole game. Here is the schema, plainly.
One row per event
The core idea is that every row is a single event, not a session and not a pageview. A page_view, a scroll, a purchase – each is its own row, stamped with who fired it and when. Sessions and pageviews are things you reconstruct from events, not columns you read directly.
The daily tables
GA4 writes one table per day, named events_YYYYMMDD, inside a dataset called analytics_<property_id>. If you enable streaming, a live events_intraday_ table holds today's data until it settles into the daily one. You query across days with a wildcard and a suffix filter.
Nested and repeated fields
The part that surprises everyone is that columns contain more columns. Two shapes appear:
- Nested RECORDs, like device and geo, which you read with dot notation: device.category.
- Repeated RECORDs (arrays), like event_params, user_properties, and items, which you have to UNNEST before you can use.
The fields you'll use most
A handful of columns carry the weight: event_name, event_date (a STRING like '20260115'), event_timestamp (microseconds), and user_pseudo_id (the device-level identifier). Traffic comes in three flavors now: traffic_source (user first-touch), collected_traffic_source (event-level UTMs), and session_traffic_source_last_click (session last-click, added July 2024).
That puzzle on first open is really just a consistent shape: one event per row, with nested and repeated fields holding the detail. Learn where the daily tables live, which fields are flat and which need UNNEST, and the GA4 export stops looking like a puzzle and starts reading like the most flexible version of your analytics you have ever had.
Want a stronger data analyst role or a raise? Grab the FREE Product Analyst Playbook and get the exact roadmap to your next offer.

