BigQuery & Integration
Export raw data to BigQuery, integrate with Google Ads, and leverage the GA4 API.
BigQuery Overview
BigQuery is Google's cloud data warehouse. GA4 offers free BigQuery export for all properties (previously only GA360).
Why Use BigQuery?
| GA4 Interface | BigQuery | |---------------|----------| | Pre-built reports | Custom SQL queries | | 14 months retention | Unlimited retention | | Sampled at high volumes | Unsampled data | | Limited joins | Join any data source | | Standard dimensions | Access ALL parameters |
What Gets Exported
Every event with:
├── Event name
├── Event timestamp
├── User pseudo ID
├── All event parameters
├── User properties
├── Device info
├── Geo info
├── Traffic source
└── E-commerce data (if applicable)Export Options
| Type | Frequency | Latency | Cost | |------|-----------|---------|------| | Daily | Once per day | ~24 hours | Lower | | Streaming | Continuous | Minutes | Higher | | Both | Daily + Streaming | Minutes | Highest |
Setting Up Export
Prerequisites
□ Google Cloud project
□ BigQuery enabled in project
□ Billing account (free tier available)
□ GA4 property admin accessStep-by-Step Setup
1. Create Google Cloud project (console.cloud.google.com)
2. Enable BigQuery API
3. In GA4: Admin → Product links → BigQuery links
4. Click "Link"
5. Select Cloud project
6. Choose export options:
├── Daily export
├── Streaming export (or both)
└── Region for data storage
7. Click "Submit"Data Structure
GA4 creates tables in BigQuery:
project.dataset.events_YYYYMMDD (daily tables)
project.dataset.events_intraday_YYYYMMDD (streaming)
Example table name:
my-project.analytics_123456789.events_20250115Cost Considerations
Free tier includes:
├── 10 GB storage free
├── 1 TB queries/month free
└── No charge until exceeded
Typical costs (if exceeded):
├── Storage: $0.02/GB/month
├── Queries: $5/TB processed
└── Streaming inserts: $0.01/200MBTip: Use the BigQuery sandbox (no credit card) for testing. Tables expire after 60 days in sandbox mode.
Querying GA4 Data
Basic Query Structure
SELECT
event_name,
COUNT(*) as event_count
FROM
\`project.dataset.events_*\`
WHERE
_TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
GROUP BY
event_name
ORDER BY
event_count DESCAccessing Event Parameters
GA4 stores parameters in nested RECORD fields:
-- Get page_location from page_view events
SELECT
event_timestamp,
(SELECT value.string_value
FROM UNNEST(event_params)
WHERE key = 'page_location') as page_location
FROM
\`project.dataset.events_*\`
WHERE
event_name = 'page_view'
AND _TABLE_SUFFIX = '20250115'Common Queries
Sessions and Users:
SELECT
COUNT(DISTINCT user_pseudo_id) as users,
COUNT(DISTINCT CONCAT(user_pseudo_id,
CAST((SELECT value.int_value FROM UNNEST(event_params)
WHERE key = 'ga_session_id') AS STRING))) as sessions
FROM \`project.dataset.events_*\`
WHERE _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'Conversion Rate:
WITH sessions AS (
SELECT
CONCAT(user_pseudo_id,
CAST((SELECT value.int_value FROM UNNEST(event_params)
WHERE key = 'ga_session_id') AS STRING)) as session_id,
MAX(IF(event_name = 'purchase', 1, 0)) as converted
FROM \`project.dataset.events_*\`
WHERE _TABLE_SUFFIX BETWEEN '20250101' AND '20250131'
GROUP BY session_id
)
SELECT
COUNT(*) as total_sessions,
SUM(converted) as conversions,
ROUND(SUM(converted) / COUNT(*) * 100, 2) as conversion_rate
FROM sessionsQuery Best Practices
□ Always filter by _TABLE_SUFFIX to limit scans
□ Use UNNEST for nested parameters
□ Create views for common queries
□ Schedule queries for regular reports
□ Use partitioned tables for large datasetsGoogle Ads Linking
Benefits of Linking
When GA4 + Google Ads are linked:
├── Import conversions to Google Ads
├── View Google Ads data in GA4
├── Export audiences for remarketing
├── Enable auto-tagging
└── Access Google Ads campaigns in reportsHow to Link
GA4: Admin → Product links → Google Ads links → Link
Configure:
├── Select Google Ads account(s)
├── Enable auto-tagging (recommended)
├── Enable personalized advertising
└── SubmitAuto-Tagging
Auto-tagging adds gclid parameter to URLs:
yoursite.com/?gclid=ABC123xyz
Benefits:
├── Accurate campaign attribution
├── Links clicks to conversions
├── Enables detailed Google Ads reports
└── Required for conversion importImporting Conversions
In Google Ads:
Tools → Conversions → New → Import → Google Analytics 4
Select:
├── GA4 property
├── Key events to import
├── Primary vs secondary statusSearch Console Integration
Why Link Search Console
Combined data shows:
├── Organic queries (from GSC)
├── Landing pages with clicks + impressions
├── Position data in GA4 reports
└── Full organic search funnelHow to Link
Admin → Product links → Search Console links → Link
Requirements:
├── Same Google account for both
├── Verified Search Console property
├── GA4 property admin accessAccessing Search Data
Reports → Acquisition → Acquisition overview → View Google organic search
Or:
Reports → Search Console → Queries/PagesAvailable Metrics
| Metric | Source | |--------|--------| | Organic search clicks | Search Console | | Impressions | Search Console | | CTR | Search Console | | Average position | Search Console | | Sessions | GA4 | | Conversions | GA4 |
API & Measurement Protocol
GA4 Data API
For programmatic access to GA4 data:
Use cases:
├── Custom dashboards
├── Automated reporting
├── Data pipelines
├── Integrations
Authentication:
├── Service account (server-to-server)
├── OAuth 2.0 (user-based)Measurement Protocol
Send events directly to GA4 from server-side:
// Server-side event example
const payload = {
client_id: 'user_123',
events: [{
name: 'purchase',
params: {
transaction_id: 'T12345',
value: 99.99,
currency: 'USD'
}
}]
};
fetch(\`https://www.google-analytics.com/mp/collect?measurement_id=G-XXXXX&api_secret=YOUR_SECRET\`, {
method: 'POST',
body: JSON.stringify(payload)
});Measurement Protocol Use Cases
| Use Case | Example | |----------|---------| | Offline conversions | CRM sale synced to GA4 | | Server-side e-commerce | Backend purchase event | | IoT devices | App-less tracking | | Refunds | Negative purchase values |
Getting API Secret
Admin → Data Streams → Select stream → Measurement Protocol API secrets → CreateIntegration Best Practices
## For API/Measurement Protocol
□ Always test in DebugView first
□ Include client_id for user association
□ Use timestamp_micros for historical events
□ Validate payload structure before sending
□ Monitor Events report for delivery confirmation
□ Keep API secrets secure (never client-side)Important: Measurement Protocol events appear in reports but NOT in Realtime (only DebugView). Allow 24-48 hours for data to fully process.