How the BigQuery export works
A GA4 property can be linked to a Google Cloud project. Once the link is live, Google writes the event rows that sit behind your reports into a dataset you own: one row per event, carrying its parameters, the device, the traffic source, the session and user identifiers and the timestamp. Nothing is rolled up or rounded off. A daily export lands the previous day’s events as a table; an optional streaming export writes them continuously as they arrive.
From there the data is read with SQL instead of clicked through in an interface. The tables are nested — event parameters and user properties sit inside repeated fields — so a query has to unnest them before those values behave like ordinary columns. That structure is the main reason the export looks harder than it really is.
Why the BigQuery export matters
The GA4 interface answers the questions Google anticipated. The export answers yours. Anything involving a sequence of events, an unusual definition of a qualified lead, a cohort followed over months, or a join to your own order or CRM data is awkward in the reports and straightforward in SQL.
It also removes two limits that appear as soon as a property gets busy: sampling in explorations and the “(other)” row that swallows values once a report holds more distinct entries than GA4 will keep. Raw rows are neither sampled nor collapsed. And because the dataset belongs to you, it keeps history after GA4’s own retention window has expired — the strongest reason to switch the export on early, even if nobody queries it for months.
Where the BigQuery export goes wrong
The commonest mistake is treating it as a backup of what you already see on screen. It is not. Figures in BigQuery rarely match the GA4 interface exactly, because the interface layers its own modelling, identity stitching and attribution on top of the raw rows. Agree that with a client before the first report is built, not after they compare two dashboards.
Cost is the other surprise. Storage is inexpensive; what you pay for is the volume each query scans, and a query that selects every column across every day of history scans all of it. Date-partitioned tables, an explicit date filter and named columns keep spending small and predictable.
The last trap is timing. The export only carries data forward from the day it is enabled, so it gives you nothing about last year. Linking it belongs in the initial GA4 setup, not in the week a difficult question finally lands.
How to act on it
Link the property, choose daily export for most sites, and add streaming only when something genuinely needs same-day rows. Set a cloud budget alert on the project the same afternoon, before anybody writes an exploratory query.
Then earn it back with one question the interface cannot answer — the true path from first visit to signed contract, say — and save that query so it can be rerun each month. If your reporting has no such question yet, the useful first step is a measurement plan and clean event naming, not SQL. Messy events export just as messily.