Why is my GA4-to-BigQuery export missing rows, or why does linking BigQuery fail with a permission error?
Quick answer
If specific dates or events are missing from your analytics_XXXXXXXXX BigQuery dataset, check whether you're querying the intraday_ table for a date that has since finalized into the daily events_ table (they don't coexist for the same day) before assuming data loss. If linking BigQuery itself fails with a 403, the account performing the link is missing the BigQuery Admin (or at minimum roles/bigquery.user plus dataset-level edit access) role in the target GCP project, not a GA4-side permission.
Why This Happens
GA4's BigQuery export runs two separate table types per day: an events_intraday_YYYYMMDD table that updates continuously through the day but can be incomplete or reprocessed, and a finalized events_YYYYMMDD table that's written once daily processing completes, typically within about 24 hours. A query written against the intraday table for a date that's since finalized, or vice versa, will look like data is missing when it's actually just in the other table.
The linking failure is a distinct, earlier-stage issue: creating the BigQuery link (via GA4 Admin > BigQuery Links, or the Admin API v1alpha bigQueryLinks resource) requires the authenticated user or service account to have edit-level IAM permissions on the destination GCP project, not just on the GA4 property. A user can be a full GA4 Administrator and still get a 403 here if they're only a Viewer on the GCP project side.
Fix It
For missing rows: confirm which table you're querying
Use a wildcard query across both prefixes for the date in question: SELECT * FROM `project.analytics_XXXXXXXXX.events_*` WHERE _TABLE_SUFFIX = '20260901' pulls from the finalized table only; add intraday_events_* as a separate check if the date is today or yesterday.
For missing rows: check the export configuration itself
In GA4 Admin > BigQuery Links, confirm the export includes the event types and (if using streaming export) that streaming is actually enabled - the free daily export and the paid streaming export are configured and billed separately, and streaming export missing doesn't mean daily export is broken.
For a 403 on linking: check IAM on the GCP project, not GA4
In Google Cloud Console > IAM & Admin for the destination project, confirm the account creating the link has at least roles/bigquery.user project-wide and edit access on the specific dataset (or roles/bigquery.admin to remove ambiguity). GA4 Administrator role alone does not grant this.
Confirm billing is enabled on the destination GCP project
BigQuery linking silently fails or the link create call errors if the target project doesn't have billing enabled - a project can exist and have correct IAM roles and still reject the link for this reason.
How To Verify It Worked
For the missing-data question: run the wildcard query above for the specific date and confirm a non-zero row count in whichever table (intraday vs. finalized) is appropriate for that date's age. A genuine gap looks like zero rows in both tables for a date that should have traffic; a timing issue looks like rows present in one table but queried from the other.
For the linking question: after fixing IAM, retry the link creation in GA4 Admin > BigQuery Links (or re-run the Admin API v1alpha call) and confirm it returns a link resource with a populated name field rather than a 403 - then check the BigQuery console for the new analytics_XXXXXXXXX dataset appearing within a day.
Still Not Fixed?
We audit and fix GA4 implementations for a living - if this doesn't resolve it, the next step is usually a full event-by-event audit.
Talk to a GA4 Consultant