GA4 BigQuery Export for SEO: The Complete Technical Guide
Learn how to connect Google Analytics 4 (GA4) to BigQuery, query raw event-level data using SQL, and build custom analyses to bypass GA4 thresholds.

Key Takeaways
- BigQuery export provides access to raw, unsampled, event-level data, bypassing GA4 interface sampling and thresholds.
- Linking GA4 to BigQuery is free, but query execution costs should be optimized by using date partitioning and select columns.
- Querying nested GA4 event parameters requires using the UNNEST SQL operator to extract attributes like page_location and traffic source.
- Combining BigQuery GA4 exports with Google Search Console data provides deep insights into user behavior and SEO page conversions.
The Google Analytics 4 (GA4) reporting interface is often a bottleneck for advanced search engine optimization and data analysts. While the standard web panel works well for basic reporting, large-scale SEO diagnostics reveal major shortcomings: data sampling, aggressive thresholding (hiding rows with small user counts), low cardinality limits leading to the dreaded (other) row grouping, and a hard 14-month data retention limit for user-level data.
To run robust, unsampled data analyses that connect search impressions to downstream conversions, exporting your raw data is essential.
By linking Google Analytics 4 to BigQuery, Google's cloud data warehouse, you gain access to raw, event-level data. In this comprehensive technical guide, we will walk through setting up the integration, decoding the nested GA4 database schema, and writing optimized SQL queries to extract deep SEO insights.
1. Why GA4 BigQuery Export is Crucial for Enterprise SEO
In modern enterprise environments, relying on standard UI metrics is a vulnerability. BigQuery shifts your reporting from aggregated estimates to granular truth.
graph TD
subgraph GA4 Standard UI Limitations
A[Browser Event] -->|1. Data Thresholds Applied| B[Aggregated Reports]
A -->|2. 14-Month Data Retention| B
A -->|3. Low Cardinality Limits| B
end
subgraph GA4 BigQuery Solution
C[Browser Event] -->|Raw Event-Level Pipeline| D[Google Cloud BigQuery]
D -->|SQL Query Processing| E[Unlimited Data Storage]
D -->|Join with GSC / CRM Data| F[True Multi-Touch Attribution]
end
Bypassing Data Thresholding
To protect user privacy, Google applies data thresholding in GA4 if your reports contain Google signals (demographic data) and have low user counts. This results in rows being completely hidden in reports. BigQuery receives the raw, un-thresholded event data, ensuring your long-tail landing pages and low-volume search queries are fully accounted for.Unsampled, Granular Event-Level Data
Standard GA4 exploration reports apply sampling when data sizes grow large. In contrast, BigQuery stores every single hit—button clicks, file downloads, scroll events, and page views—as a separate event row with its own timestamp, parameters, and user properties.Infinite Data Retention
GA4 properties limits raw data retention to a maximum of 14 months. If you need to perform year-over-year audits, run historical seasonal analysis, or evaluate multi-year organic growth trends, BigQuery allows you to retain data indefinitely.2. Step-by-Step Setup: Linking GA4 to Google Cloud BigQuery
Google provides a free, direct integration to export GA4 data to BigQuery. Below is the configuration walkthrough to link these platforms:

Step 1: Create a Google Cloud Platform (GCP) Project
- Go to the Google Cloud Console.
- Click the project dropdown in the top navigation bar and select New Project.
- Name your project (e.g.,
brand-seo-analytics) and assign it to a billing account. (Note: You can use the BigQuery Sandbox for free without a billing account, but daily exports will be capped).
Step 2: Link BigQuery inside GA4
- Navigate to the Google Analytics 4 admin interface.
- Under *Product Links*, click on BigQuery Links.
- Click the blue Link button.
- Click Choose a BigQuery project and select the GCP project you created in Step 1.
- Choose your data location (e.g.,
USorEU) to ensure GDPR compliance.
Step 3: Configure Export Settings
- →Data Streams: Select which web and app streams you want to export data from.
- →Frequency:
- →Export Type: Choose User data and/or Event data (Event data is the core requirement for SEO reporting).
3. Decoding the GA4 BigQuery Schema: Handling Nested Data
Once data begins flowing, BigQuery creates a dataset named analytics_<property_id> containing a partitioned table system named events_YYYYMMDD.
Unlike traditional relational databases where each column represents a single attribute, GA4 uses a nested event schema. Because an event can have an unlimited number of parameters, Google stores these parameters as an array of key-value pairs (RECORD data type) within a single row.
GA4 Database Structure Example:
{
"event_date": "20260701",
"event_name": "page_view",
"event_params": [
{ "key": "page_location", "value": { "string_value": "https://www.seotech.app/blog/xml-sitemaps-guide" } },
{ "key": "page_title", "value": { "string_value": "XML Sitemaps: The Complete Guide" } },
{ "key": "ga_session_id", "value": { "int_value": 1782708515 } }
],
"traffic_source": {
"medium": "organic",
"source": "google"
}
}
To extract parameters like page_location or ga_session_id, you cannot simply query SELECT page_location. You must use the SQL UNNEST operator to flatten the parameter array.
4. SQL Queries for Advanced SEO Analytics
Below are fully optimized BigQuery SQL queries designed to extract organic search metrics. Replace your-project.analytics_123456789 with your actual GCP project and GA4 dataset details.
Query 1: Extract Organic Landing Pages with Sessions and Pageviews
This query flattens theevent_params array to locate the page_location (landing page URL) and groups the results to compute total organic sessions and pageviews.
SELECT
-- Extract and clean the page location URL parameter
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location') AS landing_page,
-- Count total pageview events
COUNTIF(event_name = 'page_view') AS pageviews,
-- Calculate unique sessions using a combination of user pseudo-ID and session ID
COUNT(DISTINCT CONCAT(user_pseudo_id, (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id'))) AS sessions
FROM
`your-project.analytics_123456789.events_*`
WHERE
-- Use date partitioning to restrict data scanning and lower query cost
_TABLE_SUFFIX BETWEEN '20260601' AND '20260630'
AND traffic_source.medium = 'organic'
GROUP BY
landing_page
ORDER BY
sessions DESC;
Query 2: Page-Level Engagement Rate and Average Engagement Time
Standard engagement rates can be misleading in the GA4 UI due to thresholding. This SQL query calculates the exact average engagement time (in seconds) and engagement rate for organic visitors by URL:SELECT
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location') AS landing_page,
COUNT(DISTINCT CONCAT(user_pseudo_id, (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id'))) AS sessions,
-- Calculate Average Engagement Time in seconds
ROUND(
SAFE_DIVIDE(
SUM((SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'engagement_time_msec')),
1000
) / COUNT(DISTINCT CONCAT(user_pseudo_id, (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id'))),
2
) AS avg_engagement_seconds,
-- Calculate true engagement rate
ROUND(
COUNTIF((SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'session_engaged') = '1') /
COUNT(DISTINCT CONCAT(user_pseudo_id, (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id'))) * 100,
2
) AS engagement_rate_percentage
FROM
`your-project.analytics_123456789.events_*`
WHERE
_TABLE_SUFFIX BETWEEN '20260601' AND '20260630'
AND traffic_source.medium = 'organic'
GROUP BY
landing_page
HAVING
sessions > 10
ORDER BY
sessions DESC;
5. Joining GA4 and Google Search Console (GSC) Data in BigQuery
The ultimate benefit of using BigQuery is data consolidation. By exporting Google Search Console data into the same BigQuery project, you can join keyword performance metrics (impressions, clicks) with onsite behavior and conversion data (engagement time, sign-ups).
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "TechArticle",
"headline": "GA4 BigQuery Export for SEO: The Complete Technical Guide",
"description": "Learn how to connect Google Analytics 4 (GA4) to BigQuery, query raw event-level data using SQL, and build custom analyses to bypass GA4 thresholds.",
"inLanguage": "en-US",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://www.seotech.app/blog/ga4-bigquery-export-seo"
},
"image": {
"@type": "ImageObject",
"url": "https://www.seotech.app/images/blog/ga4-bigquery-export-seo.png",
"width": 1200,
"height": 1200
},
"datePublished": "2026-07-01T10:00:00Z",
"dateModified": "2026-07-01T10:00:00Z",
"author": {
"@type": "Person",
"name": "TechSEO Editorial Team",
"url": "https://www.seotech.app/authors/techseo-editorial-team"
},
"publisher": {
"@type": "Organization",
"name": "TechSEO Insights",
"url": "https://www.seotech.app",
"logo": {
"@type": "ImageObject",
"url": "https://www.seotech.app/images/logos/logo.svg"
}
},
"about": [
{
"@type": "Thing",
"name": "Google Analytics",
"sameAs": "https://en.wikipedia.org/wiki/Google_Analytics"
},
{
"@type": "Thing",
"name": "BigQuery",
"sameAs": "https://en.wikipedia.org/wiki/BigQuery"
},
{
"@type": "Thing",
"name": "Search Engine Optimization",
"sameAs": "https://en.wikipedia.org/wiki/Search_engine_optimization"
}
]
}
</script>
SQL Query: Linking GSC Clicks with GA4 Onsite Conversions
The following query joins the Google Search Console URL-level dataset with GA4 organic landing page conversions:WITH gsc_data AS (
SELECT
-- Normalize the URL (remove trailing slashes / parameters to match GA4)
REGEXP_REPLACE(page, r'/+$', '') AS clean_url,
SUM(clicks) AS gsc_clicks,
SUM(impressions) AS gsc_impressions
FROM
`your-project.searchconsole.searchdata_url_impression`
WHERE
data_date BETWEEN '2026-06-01' AND '2026-06-30'
GROUP BY
clean_url
),
ga4_data AS (
SELECT
-- Normalize page_location parameter to match GSC URL format
REGEXP_REPLACE(
SPLIT((SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'page_location'), '?')[OFFSET(0)],
r'/+$',
''
) AS clean_url,
COUNT(DISTINCT CONCAT(user_pseudo_id, (SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id'))) AS ga4_sessions,
COUNTIF(event_name = 'generate_lead') AS conversions
FROM
`your-project.analytics_123456789.events_*`
WHERE
_TABLE_SUFFIX BETWEEN '20260601' AND '20260630'
AND traffic_source.medium = 'organic'
GROUP BY
clean_url
)
SELECT
g.clean_url AS page_url,
g.gsc_impressions,
g.gsc_clicks,
a.ga4_sessions,
a.conversions,
-- Calculate Click-to-Session ratio to detect tracking drops
ROUND(SAFE_DIVIDE(a.ga4_sessions, g.gsc_clicks) * 100, 2) AS click_to_session_ratio,
-- Calculate conversion rate based on Google Search Console clicks
ROUND(SAFE_DIVIDE(a.conversions, a.ga4_sessions) * 100, 2) AS conversion_rate_percentage
FROM
gsc_data g
INNER JOIN
ga4_data a ON g.clean_url = a.clean_url
ORDER BY
g.gsc_clicks DESC;
This join reveals page-level friction points. For instance, a page with high GSC clicks but a low click-to-session ratio points to slow page rendering speeds, redirect issues, or tag failure. This diagnostic capability is critical for auditing website performance and identifying tracking drops, as discussed in our Website Analytics Audit Checklist.
6. SQL Query Cost Optimization and Performance Tuning
While BigQuery is highly efficient, processing gigabytes of raw event arrays can quickly run up Google Cloud costs. Follow these performance guidelines to control resource usage:
Always Use _TABLE_SUFFIX (Partition Filtering)
GA4 tables are partitioned by date. Never run SELECT * FROM events_* without a date filter. Use the _TABLE_SUFFIX system variable in the WHERE clause to restrict the search to specific daily shards:
-- Restricts the scan to June 2026, scanning only 30 tables instead of years of historical data
WHERE _TABLE_SUFFIX BETWEEN '20260601' AND '20260630'
Avoid SELECT *
Only query the specific columns you need. QueryingSELECT * reads nested fields like user_properties or items that carry heavy payload weights, inflating your cost footprint.
Materialize Common Query Tables
If you plan to run daily dashboard reporting in Looker Studio, avoid querying rawevents_* tables directly each time. Instead, run a scheduled query to summarize event data into a small, flat table once per night, and direct your reporting dashboards to query this summarized dataset.
7. Official References
- →Google Cloud BigQuery Documentation: GA4 Export Schema
- →Google Search Central: Consolidating Search Console Data in BigQuery
- →SQL Best Practices: Optimizing Query Performance in BigQuery
- →Google Analytics 4 developer guide: Querying Event Parameters
8. Conclusion
Linking GA4 to BigQuery is the single most important step in upgrading your search analytics infrastructure. By escaping the limitations of data thresholds and sampling, you build a reporting framework that provides a single source of truth.
Using the nested SQL queries provided above, you can confidently audit organic landing pages, verify user engagement times, troubleshoot click-to-session discrepancies, and build conversion-driven SEO dashboards.
To learn more about related search APIs, tracking implementations, and reporting systems, read our dedicated guides on Google Search Console API Tutorial, Server-Side Analytics Tracking, and Google Analytics 4 Guide.
Frequently Asked Questions
What are the benefits of exporting GA4 data to BigQuery?
Exporting to BigQuery unlocks unsampled, raw event-level data, overrides the GA4 interface's data thresholds and retention limits (up to 14 months), and enables joining GA4 traffic data with other sources like Google Search Console or CRMs.
Is it free to link Google Analytics 4 with BigQuery?
Yes, linking is free, and Google offers a free tier for BigQuery (10 GB storage and 1 TB query processing per month). Beyond that, standard Google Cloud pricing applies, making query optimization crucial.
How do I query nested page URLs and event parameters in BigQuery?
GA4 data is nested in record structures. To query specific attributes like page_location or user_id, you must use the SQL UNNEST operator to flatten the event_params array and extract the value from the appropriate key-value fields.
Why does GA4 UI data differ slightly from BigQuery data?
Slight discrepancies can arise due to data processing latency, timezone settings, session calculation differences, or user identifiers and data thresholds applied only in the GA4 reporting UI.

Founder & Editor, TechSEO Insights
The TechSEO Editorial Team writes practical SEO, AI tools, and web development guides based on hands-on research, testing, and real website optimization work.
Subscribe to TechSEO Insights
Get the latest guides on technical SEO, Core Web Vitals, and content marketing delivered straight to your inbox.
Privacy Note: By subscribing, you agree to receive our newsletter (Lawful Basis: Consent). We retain your email address until you choose to unsubscribe. For more details, view our Privacy Policy.


