Google Analytics and CodeWords: getting data out of GA4
Thresholding, sampling, and the cardinality limits that quietly change your numbers. What the Data API will and will not give you, and why two reports of the same thing disagree.
On this page
- What we'll cover
- Three reasons your numbers disagree
- What the GA4 Data API reaches
- Connecting it to CodeWords
- Seven automations worth building
- Reporting figures people can trust
- When to move to BigQuery instead
- Consent, and why the numbers moved
- Building it so it survives
- Limits worth knowing about
- What to build first
- Frequently asked questions
- Related reading
Automating reporting out of GA4 is straightforward until the numbers stop matching, and then it becomes an investigation. The same metric pulled twice returns different values, a figure in your automated report disagrees with the interface, and somebody loses confidence in the whole thing.
Almost always the cause is one of three behaviours that are working as designed and are not obvious: thresholding, sampling, and cardinality limits. Knowing them in advance is the difference between a report people trust and one they quietly stop reading.
What we'll cover
- Three reasons your numbers disagree
- What the GA4 Data API reaches
- Connecting it to CodeWords
- Seven automations worth building
- Reporting figures people can trust
- When to move to BigQuery instead
- Consent, and why the numbers moved
- Building it so it survives
- Limits worth knowing about
- What to build first
- Frequently asked questions
Three reasons your numbers disagree
Thresholding. GA4 withholds data that could identify individuals, which happens when a segment is small or when Google signals are enabled. The report returns fewer rows or suppressed values rather than an error, so a breakdown by a narrow dimension can quietly omit exactly the segments you were investigating.
Sampling. Large or complex queries over long ranges may be answered from a sample rather than the full data. The response indicates when this happened, and an automation that does not check will report a sampled estimate as though it were exact.
Cardinality limits. A dimension with very many distinct values collapses the long tail into an "other" bucket. A report broken down by page path on a large site can therefore show a large "other" row that changes as traffic shifts, making week-on-week comparisons unreliable at the tail.
All three are documented behaviours designed to protect privacy and performance. None produces an error. Together they explain nearly every case of two GA4 reports disagreeing.
What the GA4 Data API reaches
Reports combining metrics and dimensions over date ranges, with filters and ordering, which covers most standard reporting.
Realtime reports for the recent window, which is a different endpoint with a narrower set of dimensions.
Metadata listing the metrics and dimensions available for a property, including custom ones, which is worth reading rather than hard-coding.
Response metadata reporting whether sampling or thresholding affected the result. This is the field most automations ignore and the one that determines whether your number is trustworthy.
Audiences and the Admin API cover configuration rather than data, which matters for anything auditing how the property is set up.
Custom dimensions and metrics are available where registered, and unregistered event parameters are not queryable, which surprises people expecting to see everything they sent.
Connecting it to CodeWords
CodeWords connects to more than 3,000 integrations, and the connection is made once and reused.
- Open CodeWords and start a new automation.
- Describe what should happen in plain language to Cody, the automation builder: which property, which metrics, over what period, and where the answer goes.
- Authorize the connection with a Google service account granted read access to the property.
- Describe the exceptions: a sampled response, a thresholded result, a figure outside a plausible range.
- Run it against a period where you already know the answer and compare against the interface.
You describe the outcome; Cody builds it, connects it, and deploys it. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.
Seven automations worth building
The weekly number, delivered. The handful of metrics somebody checks anyway, with the comparison against the previous period already calculated, sent before the meeting rather than during it.
Anomaly detection against a proper baseline. Compare against the same weekday over recent weeks rather than against yesterday, since web traffic has a strong weekly rhythm and a flat comparison alarms every Monday.
Tracking health monitoring. Events that have stopped firing, conversions that have gone to zero, and traffic from a source that has vanished. Instrumentation breaks silently after releases and nobody notices for weeks.
Campaign reporting joined to outcomes. GA4 knows sessions and conversions; your CRM knows revenue. Joining them gives a figure that means something commercially.
Landing page performance digests. Which pages are gaining and losing, by segment, so content decisions have evidence.
Configuration auditing. Which custom dimensions are registered, which events are marked as conversions, and what changed. Property configuration drifts and nobody keeps a record.
Reconciliation against another source. GA4 against server-side data or your own database, reported as a difference rather than resolved. The gap is informative and consent handling usually explains much of it.
Reporting figures people can trust
The habits that determine whether an automated report survives its first challenge.
Report whether the result was sampled. Put it on the report. A number with "sampled" beside it is honest; the same number presented as exact is a credibility problem waiting to happen.
State the date range and the timezone. GA4 properties have a configured timezone and reports respect it, which is a common source of a figure that looks wrong by a day.
Be careful with users. Active users are deduplicated over the period, so weekly users do not equal the sum of daily users, and a report implying they should will be questioned.
Avoid narrow breakdowns of small segments, where thresholding withholds rows and the total no longer equals the sum of the parts.
Compare like periods. Week against week, with the same number of weekend days, rather than against an arbitrary preceding window.
Publish the definition. Which metric, which filter, which range. Most disputes about analytics figures are disputes about method.
When to move to BigQuery instead
GA4's export to BigQuery removes most of the constraints above, and it is worth knowing when to reach for it.
Sampling disappears. You are querying the event data itself rather than asking the reporting engine.
Cardinality is not collapsed. The long tail is intact.
Joins become possible. Joining analytics events against your own customer data is a query rather than an exercise in reconciliation.
Thresholding does not apply in the same way, since the export contains the underlying events.
The cost is that you are writing SQL against a moderately complex event schema, and that the export begins from when you enable it rather than covering history. For anything analytical or anything needing a join, enable the export now so the history accumulates, even if nobody queries it yet.
Consent, and why the numbers moved
A large share of "our analytics broke" reports are consent-related rather than technical, and it is worth ruling in or out early.
A consent banner change alters what is collected. More prominent rejection, a different default, or a new region covered all reduce measured traffic without anything being wrong.
Modelled data fills some of the gap, so a figure may be partly estimated rather than counted, and that estimation behaves differently from counting when you slice it finely.
Regional differences are large. A shift in traffic mix between regions with different consent behaviour moves totals without any change in actual visits.
Server-side measurement sees different things from browser-side measurement, which is a common cause of two systems disagreeing about the same week.
The reporting habit that helps: when a metric moves sharply, check whether consent configuration, banner presentation, or traffic mix changed before investigating the site. It is the first thing to rule out and the last thing most people check.
Building it so it survives
Check the sampling and thresholding metadata on every response, and surface it rather than discarding it.
Read the available dimensions from metadata rather than hard-coding names, since custom dimensions change.
Handle the empty result deliberately. Zero rows may mean no traffic or may mean a broken filter, and those are opposite situations.
Sanity check magnitudes. A figure outside a plausible range should flag rather than send, because reporting revenue as zero due to a configuration change is worse than reporting nothing.
Report the outcome. Which report ran, over what range, and whether anything was sampled.
Limits worth knowing about
Request quotas apply per property and per project, with concurrent request limits, so an automation firing many reports at once will be throttled.
Data freshness lags, particularly for the current day, so a report run at midnight for the day just ended may be incomplete.
Some metric and dimension combinations are incompatible and return an error rather than an empty result, which is confusing until you know it.
Unregistered event parameters are not queryable, so sending a parameter does not make it reportable until it is registered as a custom dimension.
Realtime uses a different endpoint with fewer dimensions, and it is not a substitute for the standard report over a recent range.
What to build first
Tracking health monitoring: events and conversions that have stopped firing or fallen sharply against their own baseline. It is read-only, it takes little building, and it catches the failure that costs most — instrumentation broken by a release, discovered weeks later when somebody asks why a number looks odd.
Two habits make the difference. Alert on absence as well as on movement, since an event going to zero is the characteristic symptom and it produces no error anywhere. And include the sampling note on every report from the beginning, so nobody ever has to ask whether a figure was estimated.
Frequently asked questions
Why does my automated report disagree with the interface?
Usually sampling, thresholding, or a timezone difference. Check the response metadata for the first two and the property's configured timezone for the third. Date range boundaries and user deduplication account for most of the rest.
What is thresholding and can I turn it off?
GA4 withholds data that could identify individuals, which affects small segments and is influenced by whether Google signals are enabled. You cannot simply disable it, and you can avoid triggering it by not breaking down small segments narrowly. The BigQuery export sidesteps it.
How do I know whether a result was sampled?
The response includes metadata saying so. Read it and put it on the report. An automation that discards that field will eventually present an estimate as exact, and the first time somebody notices, the whole report loses credibility.
Why can I not report on an event parameter I am sending?
Because it is not registered as a custom dimension. Sending a parameter makes it available in the export and not in the reporting API until it is registered, and registration is not retroactive for reporting purposes.
Should I use the API or the BigQuery export?
The API for standard recurring reports, which is most of what teams need. The export for anything analytical, anything needing a join against your own data, and anything where sampling or cardinality would distort the answer. Enable the export early regardless, since it only covers data from when you turned it on.
What is the best anomaly baseline?
The same weekday over the preceding few weeks, using a median rather than a mean. Web traffic has a strong weekly rhythm, and comparing against yesterday produces an alert every Monday that teaches people to ignore the alerts.
Can I join GA4 data with revenue?
Through the BigQuery export, straightforwardly, since both can live in the same warehouse. Through the API you can report both sides separately and present them together, which is useful and falls short of a real join.
Traffic dropped sharply with no site changes — where do I look?
Consent configuration first. A banner change, a new region covered, or a shift in traffic mix between regions all move measured totals without anything on the site changing. Rule that out before investigating tracking code.
Is modelled data a problem for reporting?
Not for trends, and it is worth knowing about when you slice finely, because modelled figures behave differently from counted ones at small volumes. Say which figures are affected rather than presenting everything as a direct count.