google analytics4 min readBy Phloz teamUpdated

GA4 says (not set), thresholded, or sampled: why your data looks incomplete

GA4 thresholding hides rows, (not set) means no value, sampling estimates from a subset. What causes each, how to fix it, and why BigQuery sees past all three.

TL;DR

Three distinct GA4 behaviours get blamed on "GA4 is broken" when they're actually working as designed — and telling them apart is the whole fix. Data thresholding: GA4 withholds rows when low numbers + Google Signals could identify individuals (you see "a threshold has been applied"). (not set): a dimension simply has no value for those rows — and the cause differs by dimension (lost source, processing timing, unregistered parameter). Sampling: large explorations estimate from a subset of data rather than all of it. None means your tracking is broken; each has a different mitigation, and the universal escape hatch for all three is the BigQuery export (raw, unsampled, unthresholded). Below: what each one is, why it happens, and what to do.


A client asks why their GA4 shows "(not set)" for a third of conversions, or why a row vanished, or why two reports of the "same" thing disagree. The instinct is that tracking is broken — but usually it's one of three built-in GA4 behaviours, each with its own cause. Diagnose which, and the panic goes away.

1. Data thresholding — GA4 is hiding rows on purpose

When a report combines low volumes with signals that could identify individuals (demographics, granular dimensions, Google Signals on), GA4 withholds the data and shows a notice ("a threshold has been applied"). It's a privacy protection, not a bug — but it makes reports look incomplete, and it's maddening on smaller sites.

Why it happens: small numbers in a report, exploration or API call that includes demographic data (which Google Signals supplies) or an audience defined by it — or low user counts on their own (Analytics Help). Older guides say to switch the reporting identity; Google Signals is no longer one of the options (Blended, Observed, Device-based), so that lever is gone.

What to do: for the affected report, reduce what triggers it — widen the date range so each row has more users, view a less granular breakdown, or drop the demographic dimension where it isn't essential. For full fidelity with no thresholding, use the BigQuery export — raw event data isn't thresholded.

2. (not set) — the dimension has no value (and why varies)

(not set) means GA4 had no value for that dimension on those rows. The cause is dimension-specific, so don't treat it as one problem:

  • Source / medium (not set) → attribution was lost: params stripped by a redirect, broken cross-domain, or a source-less server event. This is the Unassigned/traffic-attribution story.
  • Landing page (not set) → often a processing/timing artifact (the page_view and the session-start didn't line up), or a session with no qualifying page_view.
  • A custom dimension (not set) → the parameter wasn't sent on that event, or wasn't registered in time (custom dimensions aren't retroactive).

What to do: identify which dimension is (not set) and fix that specific cause — attribution capture for source, event timing for landing page, parameter registration for custom dimensions. There's no single fix because there's no single cause.

3. Sampling — estimated from a subset

GA4's standard reports are largely unsampled, but explorations over large date ranges or high-cardinality queries can apply sampling — computing from a representative subset and estimating the rest. You'll see a sampling indicator. It's usually fine directionally, but it's why two views can disagree slightly.

What to do: shorten the date range or reduce complexity to drop below the sampling threshold; use a standard report where one exists; or go to BigQuery for exact, unsampled numbers. (GA4 360 raises the thresholds, but BigQuery is the real answer.)

Adjacent to these: a dimension with too many unique values (a raw URL with query strings, a timestamp) gets its long tail bucketed into an (other) row, making it useless for analysis. The fix is upstream — keep dimension values categorical and bounded, don't shove high-cardinality data into a custom dimension.

How to explain it to a client

The client-facing version is short: "GA4 protects privacy by hiding small numbers (thresholding), labels missing values as (not set), and estimates very large queries (sampling) — none of it means we're not tracking; it means GA4's interface has limits. For the complete, exact picture we use the BigQuery export." Framing it as known platform behaviour (with a fix) rather than "something's wrong" is the difference between a confident answer and a worried client.

Where this fits

These quirks are why "is the data wrong, or is it GA4 being GA4?" is a real, recurring question — and answering it confidently requires knowing the client's setup (Google Signals, BigQuery link, custom dimensions) and what's expected. Phloz keeps each client's GA4 property (streams, links, cross-domain) modeled on the tracking-infrastructure map with a health state, and the BigQuery export — the escape hatch for all three — as a Custom node beside it, so telling "platform behaviour" from "broken tracking" starts from a verified record. The CRM for SEO agencies and pricing pages cover the workflow — but the takeaway is: thresholding, (not set), and sampling are three different things with three different causes, and BigQuery is the universal way to see past all of them.