quest_bigquery_conversational_analytics_ga4_agent.exe
_
×

Conversational Analytics in BigQuery: a GA4 Agent That Won't Lie

Conversational Analytics is GA in BigQuery. The practitioner guide to building a GA4 data agent that returns correct numbers, and what it really costs.

ga4 bigquery ai analytics guide

You point Conversational Analytics at your GA4 export, ask “how many sessions last week,” and the agent hands you a number. It looks confident. It’s wrong. Not slightly wrong: off by a factor of two, because it counted event rows instead of sessions, and nobody in the room notices. That is exactly the trap this guide is built to help you avoid.

Conversational Analytics reached general availability (GA) in BigQuery in early July 2026. Everyone is publishing the same tutorial: “Agents, Create agent, ask a question.” What nobody mentions is that on the raw GA4 export, a naive agent answers nonsense, because the schema is a minefield. Here is the protocol I use to build a GA4 data agent that returns correct numbers, publish it in Data Studio for a client, and know what it will really cost after September 30, 2026.

Conversational Analytics in BigQuery: what changed, in three dates

Three things lined up this year and turn this from theory into something you can ship.

First, Conversational Analytics has been GA in BigQuery since early July 2026. The Conversational Analytics API is in production for BigQuery and Looker: it’s past the demo stage, you can deliver.

Second, the Looker Studio to Data Studio rebrand, announced on April 10, 2026 and effective April 16, turned Data Studio into the hub of the Google Data Cloud. You now publish BigQuery conversational agents and Colab data apps right next to classic reports. That is a new distribution path: your client queries their data in plain language from inside a report, without writing a line of SQL.

Third, the free ride ends on September 30, 2026. Data Cloud Agents are on a free trial until that date; after it, billing kicks in. Test now and you get a window to evaluate without paying for tokens, as long as you know what’s coming next. More on that below.

Why an agent wired to the raw GA4 export answers wrong

The core problem is not the AI. It’s the GA4 export schema in BigQuery, which is nothing like a clean analytics table. An agent that translates your question straight into SQL over events_* will get it wrong for four specific reasons.

1. event_params is a nested, repeated field. Event parameters live in a REPEATED RECORD (event_params.key and event_params.value.string_value / int_value / and so on). To read page_location or ga_session_id, you need an UNNEST with a filter on the key. An agent that doesn’t know this structure will either ignore the parameter or count rows after UNNEST, which artificially inflates your totals.

2. There is no session table. GA4 exports events only. A session is not a row: it’s the combination of user_pseudo_id and the ga_session_id parameter. Counting sessions means counting the distinct pairs of those two values. An agent that takes “sessions” literally and looks for a sessions column won’t find one, and will improvise.

3. Traffic source lives in four places. Depending on the question, source or medium can come from traffic_source (user-level first-touch attribution), collected_traffic_source (event level), the parameters of the session_start event, or session_traffic_source_last_click on recent exports. Those four locations do not return the same result. An agent that picks at random produces an acquisition table that differs from the GA4 interface, and the client will notice.

4. Timestamps are in microseconds. event_timestamp is an integer in microseconds since the epoch, not a TIMESTAMP. Any time-based question (“in the morning,” “in July,” “by hour”) requires a conversion (TIMESTAMP_MICROS) and timezone handling. Without an explicit instruction, the agent reasons in UTC and shifts your days.

None of these four issues shows up in a demo on a clean dataset. All of them blow up on a real event export. That is why preparation matters more than the prompt.

The flattened view to build first

Rule number one: the agent never sees raw events_*. You give it a flattened view, one row per event, with the columns already extracted and named in plain terms. You move the complexity out of natural language and into SQL, once, in a place you control.

Here is a starting view, to adapt to your property:

CREATE OR REPLACE VIEW `project.dataset.ga4_events_flat` AS
SELECT
  PARSE_DATE('%Y%m%d', event_date) AS event_day,
  TIMESTAMP_MICROS(event_timestamp) AS event_ts,
  DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Europe/Paris') AS event_dt_local,
  event_name,
  user_pseudo_id,
  (SELECT value.int_value FROM UNNEST(event_params)
     WHERE key = 'ga_session_id') AS ga_session_id,
  CONCAT(user_pseudo_id, '-', CAST(
    (SELECT value.int_value FROM UNNEST(event_params)
       WHERE key = 'ga_session_id') AS STRING)) AS session_id,
  (SELECT value.string_value FROM UNNEST(event_params)
     WHERE key = 'page_location') AS page_location,
  (SELECT value.string_value FROM UNNEST(event_params)
     WHERE key = 'source') AS event_source,
  (SELECT value.string_value FROM UNNEST(event_params)
     WHERE key = 'medium') AS event_medium,
  traffic_source.source AS user_first_source,
  traffic_source.medium AS user_first_medium,
  ecommerce.purchase_revenue AS purchase_revenue
FROM `project.dataset.events_*`
WHERE _TABLE_SUFFIX >= FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 90 DAY));

Three decisions are baked into this SQL. We build an explicit session_id by concatenating user_pseudo_id and ga_session_id, so “count the sessions” becomes COUNT(DISTINCT session_id). We convert the timestamp and materialize a column in the local timezone, so time-based questions land correctly. And we pin down a source definition (here the user first-touch and the event source, clearly named), so the agent never has to guess. If your volumes are large, replace the view with a materialized table or a view partitioned on event_day: you’ll see why in the cost section.

For the full mechanics of the export and its schema traps, see the dedicated guide: the GA4 BigQuery export guide.

Creating the agent: context does all the work

In BigQuery Studio, you create it through Agents, then Create agent, pointing the agent at your flattened view rather than the raw dataset. The part that changes everything is not the button: it’s the business context you write for the agent. That is where you turn a generic SQL translator into an analyst that knows your property.

Write explicit, plain-language instructions on the definitions the agent must apply: a session is counted with COUNT(DISTINCT session_id); a “purchase” is the purchase event and revenue is read from purchase_revenue; a “key event” (formerly conversion) maps to a specific list of event_name values; the reference timezone is Europe/Paris and every time-based question uses event_dt_local; the default source is a named column. Add synonyms too (“visit” equals session, “user” equals distinct user_pseudo_id) and example questions with the expected query. The more precise the context, the less the agent improvises.

The verification protocol: knowing if the agent lies

Nobody publishes a method to verify a conversational agent. Yet it’s the only deliverable that matters before you put it in a client’s hands. The principle is simple: you ask the agent a set of questions whose answers you already know, because you have the reference SQL query beside you, and you measure the gap.

Build a battery of 8 to 10 control questions. For each one, keep the reference query and the expected number.

#Question asked to the agentWhat the reference query checks
1How many sessions last month?COUNT(DISTINCT session_id) on the right range
2How many active users?COUNT(DISTINCT user_pseudo_id)
3Top 5 most viewed pages?page_location on page_view, descending
4Total revenue in July?SUM(purchase_revenue), correct timezone
5Number of purchases last week?COUNT of event_name = 'purchase'
6Sessions by traffic source?aggregate on the pinned source column
7Purchase conversion rate per session?purchases divided by sessions, same scope
8Sessions by hour of day?hour extraction on event_dt_local

Read the gaps, not just the values. A gap of a few percent may come from rounding or a one-hour timezone shift: fixable through the context. A factor-of-two gap on sessions signals a mishandled UNNEST or row counting: the agent isn’t seeing the right definition, go back to the context. As long as one control question is wrong, the agent is not shippable. You probably already have these reference queries: reuse the ones from the 10 essential BigQuery queries.

Publishing the agent in Data Studio for the client

Once the agent is reliable, Data Studio becomes the delivery channel. Since the April 2026 rebrand, you publish the BigQuery conversational agent directly inside a report, and the client asks questions in plain language without ever touching BigQuery.

What it enables: governed self-service access. The client queries the view you prepared, with the definitions you pinned, in an environment you control. What it does not prevent: the agent stays a language engine. It can misread an ambiguous question, and it won’t invent data governance you haven’t set up. Frame the BigQuery access upstream (the agent inherits permissions on the view), and warn the client that answers should still be cross-checked on sensitive metrics. It’s a very fast assistant, not an audited source of truth.

What it really costs

Here is the number missing from every tutorial. The Data Cloud Agents free trial runs until September 30, 2026. After that, AI billing starts: $3 per million input tokens and $20 per million output tokens. On top of that, every question carries the BigQuery scan cost of the query the agent generates, billed like any query, by bytes read.

It’s that second cost that quietly spirals. An agent let loose on events_* with no partition rescans months of data on every question, and the BigQuery bill climbs far faster than the token bill. Three levers keep it in check: partition the view on event_day so the scan is limited to the requested range; materialize the flattened view rather than recomputing the UNNEST on every query; and cap the default date scope in the agent’s context. Tuned well, the agent becomes predictable on the invoice. Tuned badly, it’s a budget sieve.

So which one do you pick?

Conversational Analytics in BigQuery isn’t the only way to query GA4 in natural language, and it isn’t always the right one. Here is how I decide.

SolutionFor whomStrengthLimit
Ask Advisor (inside GA4)marketing team, quick questionszero setup, in the interfacecapped, standard GA4 scope
BigQuery agent plus Data Studiothe client, governed self-serviceraw data, pinned definitions, deliverableneeds the flattened view and context
Claude Code / MCPthe analyst, free explorationfull flexibility, no imposed guardrailsnot meant for the end client

In short: Ask Advisor for a hallway question inside GA4 (see GA4 Ask Advisor); the BigQuery agent published in Data Studio when you want to give a client reliable, framed access; and Claude Code for the data analyst or the GA4 MCP server when you’re the one digging, with no governance constraint.

The thread across all three: answer quality never depends on the tool, it depends on the data underneath. A brilliant agent on a badly prepared export is still an agent that lies with confidence. Build the flattened view, write the context, pass the control protocol, and only then deliver. You have until September 30 to test everything without paying for tokens: this is the window.