quest_ga4_missing_data_diagnosis.exe
_
×

GA4 Missing Data: Is It a Google Bug or Your Tracking?

GA4 missing data: a Google bug, broken tracking, or a real traffic drop? The 10-minute decision tree to tell them apart, plus a BigQuery monitoring pipeline.

ga4 monitoring bigquery data-quality analytics guide

On September 1, 2026, thousands of GA4 properties showed zero users in their standard reports while Realtime kept ticking along. Translation: the hits were reaching Google just fine, only the display was lying. Except most teams took 24 to 48 hours to figure that out. In the meantime, some panicked, others believed in a very real traffic collapse, and the unluckiest ones saw nothing at all because nobody was watching. In short, a textbook case of GA4 missing data: the data was right there, the display was not.

The real problem is not the incident. GA4 reporting incidents have happened before and will happen again. The problem is that when you stare at a flatline, you have to decide between three radically different hypotheses: Google has a display glitch, your collection is broken, or you genuinely lost traffic. Each one calls for the opposite reaction. This article hands you the decision tree that settles it in 10 minutes, then the monitoring pipeline that will run the diagnosis for you next time. The goal: never again mistake a Google display bug for a real tracking failure, and know which one it is before your client does.

GA4 missing data: the 3-minute test

Before the full tree, the one reflex that saves you the most time. Open GA4 and look at the Realtime report. If it shows active users while your standard reports sit at zero, you already have 80% of the answer: collection works, and it is the processing or display layer on Google’s side that is stuck. Your data is not lost, it is just not displayed yet.

If Realtime is empty too, switch mindset immediately: the problem is very likely on your end, and every minute matters because you may be losing data for good.

That single glance sets the direction for everything else. Here is how to make it reliable.

The decision tree: three cases, three verdicts

Three symptoms, three sources to cross-check, three verdicts. The table below is the condensed version; the sections that follow break down each case.

Symptom observedRealtimeDebugViewBigQuery export (D-1)Verdict
Standard reports at zero or collapsedActiveEvents visibleevents_ table present and completeCase A: Google reporting incident
Reports at zero for a whileEmptySilentevents_intraday_ missing or anemicCase B: collection broken on your side
Volume down but consistent everywhereActive, but lowEvents visibleTable present, genuinely lower volumeCase C: a real traffic drop

The reading rule is simple: Realtime tells you whether Google still receives anything right now, DebugView confirms your events are well formed, and the BigQuery export is the only place your raw hits survive a reporting incident. If all three are green and only the reports lie, you are in Case A. The moment one of those sources dries up, you shift to Case B.

Case A: a Google reporting incident (touch nothing)

This is exactly what happened on September 1. Typical signature: Realtime active, DebugView showing your events as you browse the site, and above all a BigQuery export from the previous day that is present and complete. Your hits arrived, they are stored, only the aggregation reports fail to show them.

In this case, the worst decision is to “fix” something. Do not republish your GTM container, do not touch your tags, do not launch a hunt for a bug that does not exist. You would risk introducing a real outage during an incident that will resolve on its own. What you do instead: annotate the affected period, warn the people who read the reports (client, leadership, paid team) that the display is delayed but the data is safe, and wait for reprocessing.

One important nuance: at the time of the September 1, 2026 incident, Google had not published an official confirmation or a post-mortem, and had not guaranteed an automatic backfill. Realtime stayed active, standard reports stayed at zero, with no root cause communicated. So stay factual in your own communications: “reports delayed, hits present in the raw export,” not “Google lost our data.”

Case B: your collection is broken (act fast)

The mirror signature: Realtime empty, DebugView silent even when you browse with debug mode on, and the events_intraday_ table missing or well below its usual volume in BigQuery. This is not a display problem, the hits have stopped arriving. And unlike Case A, that data is gone if you do not react.

In order of likelihood, check: a recent deploy of the site or the container (suspect number one, correlated with the exact time of the break), a GA4 tag that got unpublished or whose measurement ID changed, a consent-related block (a misconfigured CMP that blocks the tag by default sends collection to zero across the affected regions), or a tag broken by an update. For the structured list of configuration causes, it is in the GA4 audit of the 11 configuration mistakes, and the implementation-side errors are detailed in the 7 GA4 data layer mistakes.

A common trap, not to be confused with an outage: if you exceed the free export limit of one million events per day to BigQuery, Google suspends the export for that day. You then see a “hole” in your tables that looks like a break, while GA4 collection is running perfectly. If that is your case, the fix goes through direct BigQuery export via sGTM, which bypasses that limit.

Case C: it is a real traffic drop

Healthy collection (Realtime active, export complete) but genuinely lower volume: tracking is not the culprit, your traffic really did fall. Cross three sources to confirm it and understand where it comes from: Search Console for organic, your server or CDN logs for raw all-source traffic, and your ad platforms for paid.

Watch out for a sneaky sub-case: a drop in conversions without a drop in traffic. There, the culprit is usually not collection but a counting rule that changed. That is exactly what played out with the GA4 attribution changes in 2026. Likewise, if it is your costs or UTMs that are missing but not the sessions, look at GA4 campaign data import.

BigQuery, the one source of truth that survives incidents

You have noticed that in all three cases, the BigQuery export is what settles it. That is no accident. GA4 reports are an aggregation and processing layer on top of your data; when that layer falls, your reports lie. The BigQuery export, on the other hand, receives your raw hits, event by event. As long as collection works, the data lands in your tables even when the reports show zero.

In practice, two kinds of tables coexist: events_intraday_YYYYMMDD tables for the current day (freshness of a few minutes to a few hours) and events_YYYYMMDD tables frozen once the day is consolidated. During the September 1 incident, checking the presence and volume of the previous day’s table answered the “did I lose data?” question instantly. No, it was right there. If you have not wired this export yet, that is the first thing to do, and the full guide is here: work with the GA4 BigQuery export. It is the foundation of everything below.

The monitoring pipeline: diagnosing in your place

Running the test by hand once is good. Never having to run it again is better. The idea: a daily control query on the BigQuery export, scheduled, that compares yesterday’s volume to your recent normal and alerts you if the gap crosses a threshold. If these queries are new to you, the 10 essential BigQuery queries lay the groundwork before this one.

The control query

We compare the previous day’s event and session volume to the median of the trailing 28 days, per data stream. The median, not the average: an average gets distorted by a campaign spike or a slow day, whereas the median stays stable and does not fire a false alert over a plain weekend.

DECLARE low_threshold FLOAT64 DEFAULT 0.6;  -- alert if < 60% of normal

WITH daily AS (
  SELECT
    PARSE_DATE('%Y%m%d', event_date) AS day,
    stream_id,
    COUNT(*) AS events,
    COUNT(DISTINCT CONCAT(
      user_pseudo_id,
      (SELECT value.int_value FROM UNNEST(event_params)
       WHERE key = 'ga_session_id')
    )) AS sessions
  FROM `project.analytics_XXXXXX.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))
  GROUP BY day, stream_id
),
baseline AS (
  SELECT
    stream_id,
    APPROX_QUANTILES(events, 2)[OFFSET(1)] AS median_events
  FROM daily
  WHERE day < DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)
  GROUP BY stream_id
)
SELECT
  d.stream_id,
  d.events AS events_yesterday,
  b.median_events,
  ROUND(d.events / NULLIF(b.median_events, 0), 2) AS ratio,
  IF(d.events < b.median_events * low_threshold, 'ALERT', 'OK') AS status
FROM daily d
JOIN baseline b USING (stream_id)
WHERE d.day = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY);

Replace project.analytics_XXXXXX with your dataset and tune low_threshold to your tolerance. A threshold of 0.6 (alert below 60% of the median) is a good starting point for a site with stable volume; drop it to 0.4 if your traffic is highly seasonal, to avoid noise.

Schedule, threshold, alert

Once the query is solid, schedule it with a BigQuery scheduled query that writes the result to a log table, once a day after your export’s freshness window. Three ways to get the alert: wire a monitoring dashboard that reads that table (see automate your Looker Studio reporting), send a conditional email, or trigger a webhook (Slack, Teams) via a Cloud Function fired by the scheduled query. The simplest one that actually reaches you is the right one.

On cost, let us be honest: this query mostly scans light columns over 28 days of partitioned tables. On most properties, that is a few cents a day, often inside the BigQuery free tier. The monitoring that spares you a day of blindness costs less than a coffee.

What this pipeline does not catch

A moment of honesty, because promising infallibility would be dishonest. This monitoring catches volume swings: a global drop, a per-stream collapse. It does not see silent drift, when volumes stay normal but the data quietly degrades. Three blind spots to watch another way: an event parameter that starts coming in empty while the event count is stable, a spike in the unassigned source (same volume, broken attribution), and wrong monetary values with correct transaction counts. Those need targeted quality checks on the fields, not just on the counters. But for the question at hand, “did I lose my collection?”, this pipeline answers before you have even opened GA4.

The next cause of a drop is already on the calendar

A Google incident is unpredictable. An announced technical deadline is not. On October 2, 2026, the gtag('config') method stops working in certain GTM contexts, and some sites that do not prepare will see their collection break that day, with no Google bug to hide behind. If you would rather not add an avoidable Case B to your calendar, the playbook is here: gtag(‘config’) stops working on October 2, 2026. Your monitoring pipeline will catch it, but you may as well not trigger the alert for nothing.

FAQ

GA4 shows zero users, should I worry? Look at Realtime first. If it shows active users, your collection works and the problem is on Google’s display side: no emergency, annotate and wait. If Realtime is empty too, then yes, it is probably on your end and you need to act fast.

Did the September 1, 2026 GA4 bug make me lose data? In all likelihood, no, provided your collection was running. It was a reporting incident: Realtime stayed active and the BigQuery export for the period was present, which indicates the hits did arrive. At the time of writing, however, Google had not published an official confirmation or guaranteed an automatic report backfill.

How do I get alerted automatically next time? Wire a daily scheduled query on your BigQuery export that compares the previous day’s volume to the median of the last 28 days and fires an alert below a threshold (say 60%). That is the pipeline described above: it runs the diagnosis for you, before you even open GA4.

The takeaway

When you face a GA4 flatline, do not guess: test in order. Realtime to see whether Google still receives anything, DebugView to validate your events, the BigQuery export to confirm the raw data is really there. Three sources, three cases, a verdict in 10 minutes. Then do it once for good: the daily control query on BigQuery turns that manual diagnosis into an automatic alert. Next time GA4 shows zero, one notification will tell you whether it is Google or you, and you will know before your client calls.