Google BigQuery

BigQuery query examples: six sample queries you can run on GA4 data

Six BigQuery query examples that run as they are on Google's public GA4 sample dataset, so you can try them without data of your own: events, users and sessions, top pages, revenue by traffic source, best-selling items and a purchase funnel. Each comes with its real result and the one thing to change for your own export.

Google BigQueryAlyona Samovar5 min read

BigQuery query examples: six sample queries you can run on GA4 data

These six queries run as they are. They use Google’s public GA4 sample, bigquery-public-data.ga4_obfuscated_sample_ecommerce, which holds obfuscated event data from the Google Merchandise Store. Paste one into the BigQuery console and you get the result shown under it.

To use a query on your own GA4 export, change one line: the table name, to your-project.analytics_PROPERTYID.events_*.

Note: Fully rewritten in October 2026. Every result below was produced by running the query on 7 October 2026 for 1 to 7 January 2021, the period in the filter. Together the six queries read about 91 MiB.

Before you run them

Before you run them

Always filter on _TABLE_SUFFIX. The export writes one table per day, and events_* means all of them. The filter is what limits the days BigQuery reads and bills. More in wildcard tables.

Parameters are nested. Values such as the page title and the session ID sit in the event_params array, so they are read with a small subquery over UNNEST. Queries 2 and 3 show the pattern; the guide to unnesting GA4 event parameters explains it.

1. Which events are recorded, and how often

1. Which events are recorded, and how often

The first query to run on any export: what is in it.

SELECT
  event_name,
  COUNT(*) AS events,
  COUNT(DISTINCT user_pseudo_id) AS users
FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20210101' AND '20210107'
GROUP BY event_name
ORDER BY events DESC
LIMIT 5;
event_name events users
page_view 85,636 22,736
user_engagement 49,952 17,074
session_start 26,037 22,628
scroll 25,420 10,237
first_visit 20,798 20,792

The Turning Point

OWOX Data Marts

See your first report built in real time. 15 minutes.

  1. Connect your data warehouse
  2. Pick your metrics
  3. Get a live Google Sheets report

In the time it takes to write a ticket. Then imagine never writing that ticket again.

Book a Demo

We'll use your actual use case

2. Users and sessions per day

2. Users and sessions per day

GA4 has no session table. A session is a user ID plus the ga_session_id parameter.

SELECT
  event_date AS day,
  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 `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20210101' AND '20210107'
GROUP BY day
ORDER BY day;
day users sessions
20210101 2,160 2,311
20210102 2,581 2,734
20210103 2,579 2,791
20210104 3,079 3,373
20210105 4,101 4,495
20210106 5,486 6,002
20210107 4,171 4,668

Daily users do not add up to weekly users: one person on three days is counted three times here and once in a weekly COUNT(DISTINCT).

3. Most viewed pages

3. Most viewed pages

SELECT
  (SELECT value.string_value
   FROM UNNEST(event_params)
   WHERE key = 'page_title') AS page,
  COUNT(*) AS views
FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20210101' AND '20210107'
  AND event_name = 'page_view'
GROUP BY page
ORDER BY views DESC
LIMIT 5;
page views
Home 22,233
Google Online Store 9,388
Apparel | Google Merchandise Store 9,223
YouTube | Shop by Brand | Google Merchandise Store 3,731
Google Dino Game Tee 3,187

Swap page_title for page_location to group by URL.

4. Purchases and revenue by traffic source

4. Purchases and revenue by traffic source

SELECT
  traffic_source.source AS source,
  traffic_source.medium AS medium,
  COUNT(*) AS purchases,
  ROUND(SUM(ecommerce.purchase_revenue_in_usd), 2) AS revenue
FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20210101' AND '20210107'
  AND event_name = 'purchase'
GROUP BY source, medium
ORDER BY revenue DESC
LIMIT 5;
source medium purchases revenue
google organic 45 2,697
(direct) (none) 35 1,887
(data deleted) (data deleted) 23 896
shop.googlemerchandisestore.com referral 8 770
<Other> <Other> 12 755

Read this one carefully. traffic_source is the source that first brought the user, not the source of the session in which they bought. It will not match the session-based reports in the GA4 interface. That mismatch is the most common reason people think their export is wrong; see GA4 BigQuery Export mistakes. The “(data deleted)” rows are part of the obfuscation of this sample.

5. Best-selling items

5. Best-selling items

Items are a second nested array. Here it is joined to its event with a comma, which makes one row per item.

SELECT
  i.item_name,
  SUM(i.quantity) AS quantity,
  ROUND(SUM(i.item_revenue_in_usd), 2) AS revenue
FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`,
  UNNEST(items) AS i
WHERE _TABLE_SUFFIX BETWEEN '20210101' AND '20210107'
  AND event_name = 'purchase'
GROUP BY i.item_name
ORDER BY revenue DESC
LIMIT 5;
item_name quantity revenue
Google Black Cloud Zip Hoodie 9 523
Google Women’s Puff Jacket Black 3 276
Google Campus Bike 7 240
Google Sherpa Zip Hoodie Charcoal 4 220
Google Crewneck Sweatshirt Green 5 220

Do not sum ecommerce.purchase_revenue_in_usd in this query. After the unnest, an order with three items has three rows, and the order total would be counted three times. The JOIN and UNION guide calls this fan-out.

6. A purchase funnel

6. A purchase funnel

SELECT
  COUNT(DISTINCT IF(event_name = 'view_item',
    user_pseudo_id, NULL)) AS viewed,
  COUNT(DISTINCT IF(event_name = 'add_to_cart',
    user_pseudo_id, NULL)) AS added,
  COUNT(DISTINCT IF(event_name = 'begin_checkout',
    user_pseudo_id, NULL)) AS checkout,
  COUNT(DISTINCT IF(event_name = 'purchase',
    user_pseudo_id, NULL)) AS purchased
FROM `bigquery-public-data.ga4_obfuscated_sample_ecommerce.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20210101' AND '20210107';
viewed added checkout purchased
3,592 743 283 136

Of the users who viewed an item, 20.7% added one to the cart and 3.8% bought. This is an open funnel: it counts users who did each step in the week, in any order. A closed funnel, where each step must follow the one before, needs window functions; see the window functions guide.

Adapting the queries

Adapting the queries

  • Your own export: change the table name and the dates. Use FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)) in place of a fixed suffix for a rolling week.
  • Today’s data: if streaming export is on, today’s events are in events_intraday_*.
  • Cost: all six together read about 91 MiB of this small sample. On a large property, a week of events_* can be gigabytes; check the estimate the console shows before you run. See BigQuery pricing.

The link itself is covered in the GA4 to BigQuery guide, and the functions used above in the BigQuery functions map.

From sample queries to a report people use

From sample queries to a report people use

A query that works is the start. The next person to need “sessions” will write their own, and by the third copy the definitions have drifted: one counts sessions with the session ID, one counts session_start events, and the totals differ by a few percent that nobody can explain.

In OWOX Data Marts you publish the query once as a Data Mart, describe each column, and deliver it on a schedule to Google Sheets or a dashboard. Everyone reads the same sessions. OWOX Data Marts runs your SQL as written, in your own BigQuery project, and does not transform the data.

Your New Normal

Turn your data into decisions.

Governed data marts give you the clean foundation ML needs to actually work.

  • No AI hallucinations
  • Analyst-governed definitions
  • Every number traces to SQL
Get started free

Who wrote this

Alyona Samovar

Alyona Samovar · Senior Digital Analyst

Alyona Samovar is a Senior Digital Analyst who spent years at OWOX helping enterprise clients design analytics systems, build BigQuery reporting pipelines, and optimize marketing measurement. She specializes in SQL-based analytics, data modeling, and turning raw marketing data into actionable insights. Alyona writes about practical analytics workflows, BigQuery best practices, and data-driven decision-making.