PERFMETRIX — in data we trust
All articles
BigQuery11 August 2026·9 min read

GA4 BigQuery export: what the schema gives that the interface won't

Link it today even if you won't query it for months. Nothing before the link date arrives later, and the daily export caps at a million events.

DeBy Denis · Perfmetrix

Short answer: turn the export on today, on the free tier, even if nobody will write a query against it for six months. Google documents a one-time historical export for the legacy Universal Analytics link — "13 months or 10 billion hits (whichever is smaller)" (Analytics Help, checked 11 August 2026) — and documents no equivalent for GA4; what it does say is that after linking, "data should start flowing to your BigQuery project within 24 hours", and that "once you export data from Analytics to BigQuery, you cannot re-export it." Every day the link is off is a day of event-level detail you can't reconstruct. Two things to know before you rely on it: the daily export on a standard property is capped at a million events, and the export escapes the interface's thresholding partly because it doesn't contain the data that triggers thresholding in the first place.

Nothing from before the link date arrives later

The export is a tap, not an archive. It starts producing when you open it.

Google's setup instructions describe the sequence without ambiguity: "Once the linkage is complete, data should start flowing to your BigQuery project within 24 hours", and "if you enable daily export, then 1 file will be exported each day that contains the previous day's data" (Analytics Help, checked 11 August 2026). Daily tables named events_YYYYMMDD appear from then on.

We went looking for a Google page promising a backfill for GA4 and didn't find one. The legacy Universal Analytics documentation is explicit that linking a view triggered a historical export of "13 months or 10 billion hits (whichever is smaller)" and that "that export of historical data happens only once per view" (Analytics Help, checked 11 August 2026). No GA4 page makes a comparable statement. Absence of a documented backfill isn't quite proof there's never been one, but it's the only basis you should plan on — and the export page adds a line that closes the argument anyway: "Once you export data from Analytics to BigQuery, you cannot re-export it" (Analytics Help, checked 11 August 2026).

That reframes the decision. Linking is not a project. It's a checkbox you tick now so the option exists later, and the cost of ticking it early is a BigQuery dataset that sits there accumulating rows nobody reads. The cost of ticking it late is a hole in your history with your name on it.

The daily export caps at a million events, and the workaround costs you attribution

The part that gets left out of every "just enable BigQuery" recommendation.

Standard properties "have a BigQuery Export limit of 1 million events" for the daily batch export, while "there is no limit on the number of events for Streaming export" (Analytics Help, checked 11 August 2026). A busy ecommerce site clears a million events a day without trying — pageviews, scrolls, item views and every automatically collected event all count.

The escape route is the streaming export, and it isn't free in either sense. Streaming is billed at "$0.05 per gigabyte of data" (Analytics Help, checked 11 August 2026), which is the smaller problem. The larger one is what streaming leaves out: it "does not include the following user-attribution data for new users: traffic_source.name, traffic_source.source, traffic_source.medium" (Analytics Help, checked 11 August 2026).

Read that carefully if attribution is why you wanted the export. The stream that has no volume cap is the stream missing the acquisition fields for exactly the users whose acquisition you were trying to attribute. For a high-volume property the honest answer is to run both — daily for the complete records within the cap, streaming for freshness — and to know which table you're querying when you present a channel number.

event_params is a repeated record, which is why every query starts with UNNEST

The schema is the reason BigQuery feels hostile for the first hour, and it's also the reason it can answer questions the interface can't.

GA4 doesn't give each event a column per parameter. It gives you one nested, repeated record: "the event_params RECORD can store campaign-level and contextual event parameters as well as any user-defined event parameters", and it "is repeated for each key that is associated with an event" (Analytics Help, checked 11 August 2026). Each repetition holds key — "the name of the event parameter" — and a value record with typed slots underneath it.

Flattening means unnesting the array and picking the parameter you want by key:

SELECT
  event_date,
  event_name,
  (SELECT value.string_value FROM UNNEST(event_params)
    WHERE key = 'page_location') AS page_location,
  (SELECT value.int_value FROM UNNEST(event_params)
    WHERE key = 'engagement_time_msec') AS engagement_msec
FROM `project.analytics_XXXXXXXXX.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20260801' AND '20260810'

The typed slots are where the time goes. Google's schema lists string_value ("if the event parameter is represented by a string, such as a URL or campaign name, it is populated in this field"), int_value, double_value and float_value — and it says of the last one: "This field is not currently in use" (Analytics Help, checked 11 August 2026). So the defensive COALESCE that people copy from tutorials covers four fields when three are live. It does no harm; it just tells you the author copied it too. Check which slot your own parameter actually lands in before you write a query that returns nulls for a fortnight.

items behaves the same way — "the items RECORD contains information about items included in an event. It is repeated for each item" — so ecommerce queries unnest twice, once for the event's parameters and once for its items. If you're reconciling revenue, this is the layer where you find out whether the payload was complete, which is a problem worth understanding at the tagging end first.

Thresholding never touches the export — partly because the data that triggers it isn't there

The usual pitch is that BigQuery gives you everything the interface hides. Half right, and the other half is worth knowing before you promise someone demographics.

Thresholding in the interface is real and you can't switch it off. "Data thresholds are applied to prevent anyone viewing a report or exploration from inferring the identity or sensitive information of individual users", they apply when a report, exploration or API call "includes demographic data or audiences defined using demographic data", and "data thresholds are system defined. You can't adjust them" (Analytics Help, checked 11 August 2026). It's why a segment you know contains users returns a blank row.

The same page states the other half: "Analytics doesn't export data from Google signals to BigQuery" (Analytics Help, checked 11 August 2026). Signals data is what carries the demographic and cross-device signal that triggers thresholding. So the export isn't thresholded, and it also won't hand you age, gender or interest categories to analyse instead. You're trading a suppressed answer for a question the dataset doesn't hold.

What the export genuinely removes is the sampling ceiling. Sampling "may occur when the number of events used to create a report, exploration, or request exceeds the quota limit for your property", and that quota is "10 million events for standard Google Analytics properties and up to 1 billion events for Google Analytics 360 properties" (Analytics Help, checked 11 August 2026). Explorations are where a mid-sized property meets that wall. The daily export contains the raw event rows, so your query reads all of them or none.

The export is complete about what arrived and silent about what never left the browser. A tag blocked by the CMP, or firing before consent, changes what's in your dataset — and no SQL will show you the events that were never sent. Our free cookie and tracker scanner loads your site in a real browser and reports which trackers fire before and after consent, and which CMP is actually enforcing, which is the check to run before you treat a BigQuery table as ground truth.

Expect a discrepancy of a few per cent and stop chasing it

Two numbers from two systems will disagree, and Google publishes the tolerance.

"A discrepancy of 2-5% between the total event count in Analytics and BigQuery is expected" (Analytics Help, checked 11 August 2026). Inside that band, stop. Outside it, Google's own troubleshooting list is about configuration rather than mystery: check the link is live, check the reporting identity is set to Device ID when comparing, check the time zones match, and check no data stream or event has been excluded from the export.

The time-zone one causes more confusion than the rest combined, because a daily table boundary that doesn't match a report's day boundary produces a stable, plausible, entirely wrong difference on every single day.

What to do this week

Link the property to BigQuery, enable the daily export, and leave it. It takes a few minutes, the free tier absorbs a lot of storage, and it starts the clock on a history you can't create retrospectively.

If your property clears a million events a day, decide now whether you're adding the streaming export and write down that new-user traffic-source fields are absent from it, because that footnote will otherwise reappear as a mystery in a channel report six months from now. And before you present anything from the dataset, confirm what your tagging layer is sending under each consent state — a query is only as honest as the events that reached Google. That repair work, from the consent layer through to what bidding sees, is what we do.

Sources

  1. 1.Analytics Help — [GA4] BigQuery Export (daily and streaming, limits, re-export) · Checked 2026-08-11
  2. 2.Analytics Help — [GA4] Set up BigQuery Export · Checked 2026-08-11
  3. 3.Analytics Help — [GA4] BigQuery Export schema (event_params, items) · Checked 2026-08-11
  4. 4.Analytics Help — [GA4] Data thresholds · Checked 2026-08-11
  5. 5.Analytics Help — [GA4] About data sampling · Checked 2026-08-11
  6. 6.Analytics Help — [GA4] Compare Analytics reports and data exported to BigQuery · Checked 2026-08-11
  7. 7.Analytics Help — [UA] Set up BigQuery Export [Legacy] (the one-time historical export) · Checked 2026-08-11

Find out what your site leaks — in 30 seconds

Run the free consent checker on your own domain, or book a call and we'll walk your setup together.