All posts
5 min readga4, bigquery, data-warehouse

Streaming GA4 into BigQuery: when raw event data is actually worth it

GA4's free BigQuery export is one of its best features and most over-hyped. Raw event-level data unlocks analysis the UI can't touch — and a maintenance surface most teams underestimate. Here's when it's worth it.


The GA4 BigQuery export gives you every raw event, unsampled, unthresholded, with every parameter — the data behind the interface rather than the interface's summary of it. It is worth turning on for almost every property, because it costs little and starts accumulating history the day you enable it. Whether it is worth querying depends on whether you have questions the GA4 interface genuinely cannot answer.

What the export actually gives you

One row per event, with nested fields for event parameters, user properties, items, device, geography, and traffic source. No sampling. No data thresholding hiding rows. No 300-name limits or cardinality collapse into an "(other)" bucket.

That last point is the one people underestimate. GA4's interface applies thresholds that withhold rows to protect user privacy, collapses high-cardinality dimensions, and samples some explorations at volume. BigQuery does none of that — you are reading what was collected.

The catch: it is not retroactive. Enabling it today gives you data from today. This is why "turn it on now, decide later" is the correct default even if you have no immediate use for it.

When BigQuery is genuinely worth it

  • Joining tracking data to business data. Revenue in GA4 versus revenue in your finance system; sessions joined to CRM lead status; behaviour joined to customer lifetime value. This is the single biggest reason, and the interface cannot do it at all.
  • Custom attribution. GA4 gives you its models. In BigQuery you can build your own, with your own windows and rules, over the raw touchpoint sequence.
  • Escaping thresholds and sampling. If your reports show "(other)" rows or withheld data, the answers are still in BigQuery.
  • Long retention. GA4's event-level retention is limited; BigQuery keeps data as long as you pay for storage.
  • Auditing what was actually collected. The fastest way to answer "is this parameter really being sent?" for historical periods.
  • Feeding models and machine learning — propensity scoring, LTV prediction, anything needing event-level input.

When it is not worth the effort

  • You need standard reports and the interface answers your questions.
  • Nobody on the team writes SQL, and nobody is going to.
  • Your traffic is small enough that thresholding and sampling never bite.
  • You are hoping it will fix bad tracking. It will not. BigQuery faithfully stores whatever your tags sent, including the wrong values.

That last point deserves emphasis: exporting broken data gives you broken data with better retention.

Setting it up

  1. Create or choose a Google Cloud project, and enable billing. The export itself has no GA4-side cost; you pay BigQuery's storage and query prices.
  2. In GA4: Admin → Product links → BigQuery links → Link. Choose the project, the location, and the data streams.
  3. Choose the export type. Daily is a complete, ordered table per day. Streaming is continuous with near-real-time availability, costs more, and produces a separate intraday table.
  4. Wait. The first daily export lands within about 24 hours.

Most properties want daily only. Add streaming when you have a genuine real-time need — operational alerting, live dashboards — not because faster sounds better.

The table shape, briefly

Events land in events_YYYYMMDD tables, with intraday tables when streaming is on. The fields that matter most on day one:

FieldContains
event_nameThe event
event_timestampMicroseconds since epoch
event_paramsRepeated key/value — your parameters live here
user_pseudo_idThe client ID
user_idYour own ID, if you send one
itemsRepeated ecommerce items
traffic_sourceFirst-touch source, not per-session
device, geoNested structs

Parameters are a repeated field of key/value pairs, which is why almost every GA4 query starts with an UNNEST:

SELECT
  event_date,
  COUNT(*) AS purchases,
  SUM((SELECT value.double_value FROM UNNEST(event_params)
       WHERE key = 'value')) AS revenue
FROM
  analytics_123456789.events_*
WHERE
  _TABLE_SUFFIX BETWEEN '20260701' AND '20260731'
  AND event_name = 'purchase'
GROUP BY event_date
ORDER BY event_date

Note the wildcard table with a _TABLE_SUFFIX filter — that filter is what stops you scanning every day you have ever collected.

Controlling cost

BigQuery charges for bytes scanned, and GA4 tables are wide. Three habits keep the bill trivial:

  1. Always filter on _TABLE_SUFFIX. Querying events_* without a date bound scans your entire history, every time.
  2. Select only the columns you need. SELECT * on a nested GA4 table is the most expensive thing you can casually type.
  3. Materialise the queries you run often into small daily summary tables, and point dashboards at those rather than at raw events.

For most properties, following those three rules keeps monthly cost in the range of a coffee.

The one thing to do today

Turn it on. Even if you have no immediate question, the export costs almost nothing while unused, and the history it accumulates cannot be recreated later. The most common regret with BigQuery is not enabling it two years earlier — the interface only keeps event-level detail for a limited window, and GA4's data retention setting is quietly deleting the rest.

FAQ

Does the GA4 BigQuery export cost money?

The export itself is free from GA4's side. You pay Google Cloud for storage and for bytes scanned by queries. With date-filtered queries and summary tables, most small and mid-sized properties spend very little.

Can I get historical data when I enable the export?

No. The export is not retroactive — it begins from the day you link it, which is the main argument for enabling it before you need it.

Do I need streaming export or is daily enough?

Daily is enough for almost everyone. Streaming costs more and is worth it only when you have a real-time operational need rather than a preference for fresher numbers.

Why do my BigQuery numbers not match the GA4 interface?

Expected, and usually explainable: the interface applies thresholding, sampling, and its own attribution modelling, while BigQuery holds raw events. BigQuery is closer to what was collected; the interface is closer to what GA4 reports.

Do I need to know SQL to use the BigQuery export?

To query it directly, yes. You can point Looker Studio at BigQuery for visual reporting, but the value of the export is mostly in questions that require SQL — if nobody will write any, enable the export for the history and revisit later.

Before exporting anything, make sure what you are collecting is correct: the free tracking audit checks GA4 presence, duplicate properties, and consent signals on any URL.


See where your tracking stands

Run the same 13-check audit referenced in this post against any URL. No signup, results in seconds.

Run a free audit