Connecting data
Google Analytics 4
Connect GA4 through its BigQuery export, and understand the tables, settling window and cost controls.
GA4's reporting API only returns aggregates. They're capped, sampled over long date ranges, and fold rare values into (other). The only way to get event-level data out of GA4 is its BigQuery export, so that's what Datachef reads. Two things have to exist before you connect.
1. Link GA4 to BigQuery
In GA4, go to Admin → Product links → BigQuery links → Link. Choose a Google Cloud project, turn on the daily export (and the streaming export if you want today's data too), and save. The first events_YYYYMMDD table appears about a day later.
The export isn't backfilled. It holds data from the day you link it, and nothing earlier, so link it before you need the history.
2. Create a service account
In that Google Cloud project, create a service account and give it two roles:
| Role | Where |
|---|---|
| BigQuery Data Viewer | On the analytics_<property id> dataset |
| BigQuery Job User | On the project that runs the queries |
Then download a JSON key for the service account. Job User is the role people usually forget. The connection test runs a free dry-run query, so if the role is missing you'll find out when you save, not at the first sync.
Connection fields
| Field | Notes |
|---|---|
| Google Cloud project | The project that holds the export dataset |
| Billing project | Leave blank unless the queries should be billed to a different project, for example when the export is shared to you from another project |
| Export dataset | analytics_<property id> |
| Service account key | Paste the whole JSON key |
| Sync data from | Defaults to one year ago |
| Days to let a shard settle | Defaults to 3. See below. |
| Days per query | Optional. Leave blank unless you want smaller queries. |
| Max GB scanned per query | A hard ceiling. BigQuery refuses a query it estimates would scan more, instead of billing you for it. |
Tables
You get one table per export family, not one per day:
| Table | Present when | Sync modes |
|---|---|---|
events | Always | Incremental or full refresh |
events_event_params, events_items, events_user_properties | Always | Incremental or full refresh |
events_intraday (and its child tables) | The streaming export is on | Full refresh only |
users, pseudonymous_users (and their child tables) | The user-data export is on | Incremental or full refresh |
Nested records are flattened to one column per field, so device.category becomes device_category. Each repeated field, such as event_params, becomes a table of its own with one row per element. It keeps its parent's key columns so you can join back to the event.
This is event-level data, not GA4's reports. There are no pre-computed sessions or channel groupings, so you compute them in SQL. The agent knows the export's schema and can write those queries for you.
The settling window
GA4 keeps adding events to a day's table for up to 72 hours after the day ends. An incremental sync waits until a day has settled before reading it, and then never reads that day again. Data lands a few days late, but it lands once and complete. With the default of 3 days, the table for the 1st is read on the 6th. The extra two days allow for the property's timezone.
A full refresh doesn't wait, because it replaces the whole table each time.
Keeping BigQuery costs down
BigQuery bills for the bytes a query scans:
- Columns you don't sync aren't scanned, so they aren't billed.
- Syncs are filtered by day, so BigQuery skips whole days that aren't needed.
- Max GB scanned per query caps any one query.
Trying it without a GA4 property
Google publishes an export of its merchandise store as a public dataset. You can use it to try the connector:
| Field | Value |
|---|---|
| Google Cloud project | bigquery-public-data |
| Billing project | Any project of yours with BigQuery enabled. A free BigQuery sandbox project works. |
| Export dataset | ga4_obfuscated_sample_ecommerce |
| Sync data from | 2020-11-01 |
The data ends in early 2021, so you have to set Sync data from. With the default of one year ago, nothing is found.
Something missing or wrong on this page? Tell us