Skip to content
Data

Data quality monitoring: catch broken tracking before reports do

How to monitor tracking data quality across GA4, Google Ads, Meta and BigQuery: built-in alerts, BigQuery checks and a routine that catches breaks early.

By Dimitris8 min read
Catch the break across four layers. Flat editorial diagram of the article’s measurement workflow.
Tracking Whisper
The short answer

Monitor tracking in four layers: whether tags load, whether event volumes look normal, whether key parameters are filled, and whether data reaches each platform and warehouse on time. GA4 custom insights, Google tag diagnostics, Google Ads conversion statuses and Meta Events Manager diagnostics cover part of this for free, and a few scheduled BigQuery queries cover the rest, so a broken tag shows up within a day rather than at month-end.

Tracking rarely fails loudly. A developer renames a button class, a consent banner update stops firing a trigger, a checkout moves to a new domain, and the purchase event quietly disappears. The first person to notice is often a client asking why last week's revenue halved. Data quality monitoring turns that around: you get told within hours, while the fix is still cheap.

What actually breaks tracking?

From audits and incident reviews, the causes fall into a short list:

  • Site releases. Changed selectors, removed dataLayer pushes, a new checkout template, a single-page app route that no longer triggers a page view.
  • Consent changes. A CMP update that no longer sends the consent update, or a trigger that now waits for a consent state that never arrives.
  • Tag Manager changes. A paused tag, a broken variable, a workspace published with an old version of a trigger.
  • Connections and credentials. An expired OAuth grant for a reporting connector, a BigQuery billing issue, an offline conversion import that started failing.
  • Platform changes. API sunsets and migrations, such as the move of offline conversion imports to the Data Manager API.

Each of these shows up in a different place, which is why one alert is not enough.

What should a monitoring setup cover?

Think in four layers, from the browser to the report:

LayerQuestionTypical signalWhere to check
CollectionDo tags load and fire on key pages?Tag missing, request not sentReal browser checks, Google tag diagnostics
VolumeDo event counts look normal?Key event drops to zero or halvesGA4 custom insights, BigQuery
ContentAre the parameters filled and valid?Missing transaction_id, zero value, no itemsBigQuery, GA4 explorations
DeliveryDid data reach every platform and table on time?Late export, inactive conversion actionGoogle Ads statuses, Meta diagnostics, BigQuery metadata

A setup that covers only volume will miss a purchase event that still fires but with an empty value. A setup that covers only collection will miss a working tag whose data never reaches Google Ads.

Four layers of tracking quality: A healthy tag alone does not prove that valid data reaches the warehouse.
Tracking Whisper
A healthy tag alone does not prove that valid data reaches the warehouse.

Which built-in alerts are worth switching on?

Start with what the platforms already give you. It costs nothing and covers a surprising amount.

GA4 custom insights

GA4 lets you create up to 50 custom insights per property. Each one evaluates a metric on a schedule (hourly, daily, weekly or monthly, with hourly available only for web data) and can email named users when the condition is met.

  1. In GA4, on the Insights card, click View all insights, then Create.
  2. Choose the evaluation frequency. Use Hourly for the key events of a busy website, Daily for lower volumes.
  3. Set the segment (for example, all users, or one country for a multi-market site).
  4. Choose the metric, for example the key event count for purchase or generate_lead.
  5. Choose the condition. Has anomaly lets GA4 decide what is unusual. A fixed condition, such as a percentage decrease beyond a threshold you choose, is easier to reason about.
  6. Name it clearly, add the email addresses and switch notifications on.

For hourly anomalies, Google's documentation says the model trains on two weeks of data and flags a value outside the predicted credible interval. That is useful for sudden drops but weak for slow declines, and it needs a stable history. Create one anomaly insight and one fixed-threshold insight for each critical event.

Google tag diagnostics and tag coverage

In Google tag settings, Tag quality has a View diagnostics link. Statuses run from Excellent and Good to Urgent, and Google gives "the Google tag hasn't been detected in the last 48 hours" as an example of an Urgent issue. The Tag coverage summary lists pages as Tagged, No recent activity (no tag load in the last 30 days) or Not tagged. Review it after every site migration or new template.

In Google Ads, the conversions summary shows a status for each conversion action. The ones to act on are Misconfigured (conversions have stopped recording because of a setup error), Needs attention (still recording, but with an issue to fix) and Awaiting conversions (nothing recorded in the last seven days). The last one is sometimes legitimate for a low-volume action, but on your main purchase or lead action it is an alarm.

Meta Events Manager diagnostics

The Diagnostics tab in Events Manager lists issues for web, app and offline events. Critical issues carry a red icon and warnings a yellow one. Check it weekly and after every change to the pixel or Conversions API setup.

How fast can you expect to see a break?

Monitoring is limited by when the data arrives. Google's GA4 data freshness page gives these typical times:

DataTypical freshness
Intraday, Analytics 360About 1 hour
Intraday, standard properties2 to 6 hours
Daily, most propertiesAbout 12 hours
Daily, properties with large data limits18 to 24+ hours

The same page gives typical times of day in the property's time zone: daily BigQuery events around midday and daily data in standard reports mid-afternoon. Schedule your BigQuery checks after the export normally lands, not at midnight.

Monitoring alert example: A required field is missing. Illustrative interface with synthetic example data.
Tracking Whisper
Send the alert with the failing payload and an owner who can verify the recovery. Illustrative interface; synthetic data, not a live report.

Which BigQuery checks catch what alerts miss?

If you export GA4 to BigQuery, four scheduled queries cover most of the gaps. Replace my-project.analytics_123456789 with your project and dataset.

1. Key event volume against recent history

This compares yesterday's count of each key event with the same event over the previous 28 days. The date spine makes sure a day with zero events still appears, which is the case you most need to catch.

WITH days AS (
  SELECT day, event_name
  FROM UNNEST(GENERATE_DATE_ARRAY(DATE_SUB(CURRENT_DATE(), INTERVAL 29 DAY),
                                  DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))) AS day
  CROSS JOIN UNNEST(['purchase', 'generate_lead', 'sign_up']) AS event_name
),
counts AS (
  SELECT
    PARSE_DATE('%Y%m%d', event_date) AS day,
    event_name,
    COUNT(*) AS events
  FROM `my-project.analytics_123456789.events_*`
  WHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 29 DAY))
                          AND FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
    AND event_name IN ('purchase', 'generate_lead', 'sign_up')
  GROUP BY day, event_name
),
filled AS (
  SELECT day, event_name, IFNULL(c.events, 0) AS events
  FROM days AS d
  LEFT JOIN counts AS c USING (day, event_name)
)
SELECT
  event_name,
  MAX(IF(day = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY), events, NULL)) AS yesterday,
  ROUND(AVG(IF(day < DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY), events, NULL)), 1) AS avg_previous_28d,
  ROUND(SAFE_DIVIDE(
    MAX(IF(day = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY), events, NULL)),
    AVG(IF(day < DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY), events, NULL))
  ), 2) AS ratio_to_average
FROM filled
GROUP BY event_name
ORDER BY ratio_to_average;

Flag any ratio below about 0.5 for a high-volume event. For low volumes, compare weekly totals instead, or a single quiet day will trigger false alarms.

2. Purchase parameter completeness

A purchase event that fires without a transaction ID or value is worse than one that does not fire, because it looks fine in event counts.

SELECT
  PARSE_DATE('%Y%m%d', event_date) AS day,
  COUNT(*) AS purchase_events,
  COUNTIF(ecommerce.transaction_id IS NULL OR ecommerce.transaction_id IN ('', '(not set)')) AS missing_transaction_id,
  COUNTIF(IFNULL(ecommerce.purchase_revenue, 0) = 0) AS zero_revenue,
  COUNTIF((SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'currency') IS NULL) AS missing_currency,
  COUNTIF(ARRAY_LENGTH(items) = 0) AS no_items,
  COUNT(*) - COUNT(DISTINCT ecommerce.transaction_id) AS repeated_or_null_ids
FROM `my-project.analytics_123456789.events_*`
WHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 14 DAY))
                        AND FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
  AND event_name = 'purchase'
GROUP BY day
ORDER BY day DESC;

A rise in repeated_or_null_ids usually means duplicate purchases from page reloads or a second tag. Our article on duplicate purchase events in GA4 walks through the fixes.

3. Export freshness

If the daily table has not landed, every downstream report is stale. This reads table metadata and costs almost nothing.

SELECT
  MAX(table_name) AS latest_daily_table,
  MAX(creation_time) AS latest_created_at,
  TIMESTAMP_DIFF(CURRENT_TIMESTAMP(), MAX(creation_time), HOUR) AS hours_since_last_table
FROM `my-project.analytics_123456789`.INFORMATION_SCHEMA.TABLES
WHERE REGEXP_CONTAINS(table_name, r'^events_\d{8}$');

Alert when hours_since_last_table exceeds about 36. Daily tables can be updated after creation when late events arrive, so use this as a "did the export run" check, not as a completeness check.

A broken consent banner often shows up as a sudden shift in the share of events with analytics storage granted. The export schema records it in privacy_info.analytics_storage with the values Yes, No or Unset.

SELECT
  PARSE_DATE('%Y%m%d', event_date) AS day,
  IFNULL(privacy_info.analytics_storage, 'null') AS analytics_storage,
  COUNT(*) AS events,
  ROUND(100 * COUNT(*) / SUM(COUNT(*)) OVER (PARTITION BY event_date), 1) AS pct_of_day
FROM `my-project.analytics_123456789.events_*`
WHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 14 DAY))
                        AND FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))
GROUP BY event_date, analytics_storage
ORDER BY day DESC, analytics_storage;

You are looking for change, not a target number. A jump in Unset after a CMP update is worth a look the same day. The Consent Mode v2 checklist covers what correct behaviour looks like.

Run these as BigQuery scheduled queries writing to a small results table, then alert from that table, or have your monitoring tool read it.

Why check key pages in a real browser as well?

Data checks tell you that something broke, usually a day later. A browser check tells you what broke, before data is lost. Once a day, or after every release, load the pages that matter (home, a product or service page, the form or checkout confirmation) in a real browser and confirm:

  1. The GTM container and Google tag load.
  2. The expected dataLayer events are pushed with the right keys.
  3. The GA4, Google Ads and Meta requests are sent with the expected parameters.
  4. Consent defaults are set before tags fire, and the update is sent when the banner is accepted.

This is the only layer that catches a problem on a page with low traffic before the data shortfall is large enough to be visible.

Who should get the alert, and what happens next?

An alert that goes to a shared inbox nobody reads is worse than none, because it creates false confidence. Agree three things per client or property:

  • Owner. One named person who acknowledges the alert the same working day.
  • Severity. "Purchase event at zero" is urgent. "Currency missing on 2% of purchases" can wait for the weekly review.
  • Runbook. The first three checks to make: was there a release, did the GTM container change, does the browser check pass.

Log every incident with its cause and the time to detection. After a quarter, that log tells you which layer to strengthen. Ahead of peak periods, our Black Friday tracking checklist covers what to verify while there is still time to fix it.

Give every alert a next action: Route the evidence to an owner, investigate and verify the recovery.
Tracking Whisper
Route the evidence to an owner, investigate and verify the recovery.

Key takeaways

  • Monitor four layers: collection, volume, content and delivery. Each catches failures the others miss.
  • Switch on the free signals first: GA4 custom insights (up to 50 per property, hourly for web), Google tag diagnostics, Google Ads conversion statuses and Meta's Diagnostics tab.
  • Expect GA4 intraday data in 2 to 6 hours and daily data in about 12 hours for most standard properties, and schedule checks accordingly.
  • Use a date spine in BigQuery volume checks so a day with zero events is reported, and check parameter completeness, export freshness and consent share.
  • Give every alert an owner, a severity and a short runbook.

Tracking Whisper's monitoring runs this kind of routine across GTM, GA4, Google Ads, Meta and BigQuery: it checks key pages in a real browser for dataLayer events, hits and consent, and alerts when tracking stops. An initial audit is the usual starting point for deciding which events and pages to watch.

Frequently asked questions

How do I get alerted when GA4 tracking stops?

Create a custom insight in GA4 for your key events with the condition Has anomaly or a fixed threshold, and turn on email notifications. Hourly evaluation is available for web data. Back it up with a daily BigQuery check, because an anomaly model needs history and can miss gradual declines.

How quickly does GA4 show that something broke?

Google's data freshness documentation gives two to six hours for intraday data in standard properties and around 12 hours for daily data in most properties. So a break that happens in the morning is usually visible in intraday data the same day, and in the complete daily tables the next day.

What does Urgent mean in Google tag diagnostics?

It is the most severe tag quality status. Google uses it for critical problems such as the Google tag not being detected in the last 48 hours, which means data has dropped to zero. Open Google tag settings and select View diagnostics to see the issue and suggested fix.

Which tracking checks should run every day?

At minimum: event counts for each key event compared with recent history, completeness of the purchase or lead parameters, the time the latest BigQuery export table landed, and the status of conversion actions in Google Ads. These four catch most breaks caused by site releases, consent changes and expired connections.

Is a drop in conversions always a tracking problem?

No. Campaign changes, stock-outs, a pricing change or simply a bank holiday can reduce real conversions. Monitoring should flag the drop, then a person checks whether page views and add-to-cart events fell in proportion (a real demand change) or whether only the final event vanished (usually tracking).

Sources

  1. [GA4] Analytics Insights, Analytics Help
  2. [GA4] Anomaly detection, Analytics Help
  3. [GA4] Data freshness, Analytics Help
  4. Troubleshoot tag issues with Tag Diagnostics, Tag Manager Help
  5. About the Tag coverage summary, Tag Manager Help
  6. Troubleshooting conversion tracking status, Google Ads Help
  7. About Diagnostics in Facebook Events Manager, Meta Business Help Centre
  8. BigQuery Export schema, Analytics Help
Written byDimitrisTracking Whisper

Dimitris builds Tracking Whisper and writes about tracking, analytics and data from the work the agent does every day: GTM containers, GA4 properties, ad platforms and the numbers in between.

Give Whisper its first job.

The free plan covers one site. Start with a setup, an audit or a question about your numbers. No card needed.