artifact #A-004 · sql · current
GA4 BigQuery: sessions with last-click source and key events
One query over the events_* export: sessions per day, the session's last-click source from the record Google added in July 2024, and key events per session.
- verified_on
- 2026-09-09
- checked against
- GA4 BigQuery export schemaGA4 What's new archive — Jul 19, 2024 (session traffic source record)GA4 What's new archive — Oct 22, 2024 (session-scoped fields)
- next re-check
- 2026-12-01
- status
- current
- time
- 15 minutes
- skill
- you can run a BigQuery query
What's inside
- ga_session_id from event_params; session_traffic_source_last_click for source and Ads campaign
- session_start check so you can see sessions without a start event
- key events counted from event names (edit the list) — the March 2024 vocabulary
Install
- Replace PROJECT and PROPERTYID; set the two dates.
- Edit the key-event names in COUNTIF to your property's key events.
- Run in BigQuery; compare the totals with Reports › Traffic acquisition for the same dates (small differences are normal: the export is unsampled and not thresholded).
The file · ga4-sessions-key-events.sql
-- GA4 BigQuery export: sessions per day with last-click session source, and key events per session.
-- Schema: events_YYYYMMDD; session_traffic_source_last_click record (added Jul 2024); "key events" = GA4's renamed conversions (Mar 2024).
DECLARE start_date STRING DEFAULT '20260801';
DECLARE end_date STRING DEFAULT '20260831';
WITH base AS (
SELECT
PARSE_DATE('%Y%m%d', event_date) AS day,
user_pseudo_id,
(SELECT value.int_value FROM UNNEST(event_params) WHERE key = 'ga_session_id') AS ga_session_id,
event_name,
session_traffic_source_last_click.manual_campaign.source AS ss_source,
session_traffic_source_last_click.manual_campaign.medium AS ss_medium,
session_traffic_source_last_click.google_ads_campaign.campaign_name AS ads_campaign
FROM `PROJECT.analytics_PROPERTYID.events_*`
WHERE _TABLE_SUFFIX BETWEEN start_date AND end_date
),
sessions AS (
SELECT day, user_pseudo_id, ga_session_id,
ANY_VALUE(COALESCE(ads_campaign, ss_source)) AS source_or_campaign,
ANY_VALUE(ss_medium) AS medium,
COUNTIF(event_name = 'session_start') > 0 AS has_start,
COUNTIF(event_name IN ('purchase', 'generate_lead')) AS key_events -- edit: your key events
FROM base
WHERE ga_session_id IS NOT NULL
GROUP BY day, user_pseudo_id, ga_session_id
)
SELECT day, source_or_campaign, medium,
COUNT(*) AS sessions,
COUNTIF(has_start) AS sessions_with_start,
SUM(key_events) AS key_events,
SAFE_DIVIDE(SUM(key_events), COUNT(*)) AS key_events_per_session
FROM sessions
GROUP BY day, source_or_campaign, medium
ORDER BY day, sessions DESC; Breaks on
The logged changes that can invalidate this artifact. A new one triggers a re-check.
Stamped 9 Sept 2026 · re-checked quarterly or on change · corrections to team@datameasured.com · ← the library