Data discrepancies between properties after migrating GA4 e-commerce events from one container to another.
Audit of 21 tags, 64 triggers, and 177 variables: three data-exclusion causes running in parallel (a global toggle variable, a 35-ID regex blacklist, and an independent blocked-sites table).
Validated export with recursive dependency resolution and cleanup of legacy Universal Analytics tags.
Container reduced from 177 to 102 variables and 21 to 7 tags, with zero broken references. Architecture built to scale to thousands of client containers.
Context
This wasn’t a one-off migration — it was meant to be the template for thousands of client containers. That changed what "success" meant: it wasn’t enough for the migration to work once, it had to be a repeatable process that didn’t require rediscovering the same problems from scratch every time.
How it was actually solved
Three exclusion systems nobody had ever cross-checked
The toggle variable, the 35-ID regex blacklist, and the blocked-sites table were added at different times, for different reasons, with no documentation tying them together. Each one looked intentional on its own. Together, they silenced data in overlapping ways — making it nearly impossible to tell, from the final numbers alone, which of the three was acting in any given case.
What "recursive dependency resolution" means in practice
Before moving any tag, its full chain was traced: what variables it reads, what those variables in turn depend on, and what triggers use them in their conditions. Migrating without that mapping is the most common reason a tag arrives in the new container but silently stops firing — a broken reference throws no error, it just stops working.
Why cutting variables wasn’t the goal, it was the outcome
Going from 177 to 102 variables wasn’t a "cleanup" target — it was what remained after removing exactly the duplicated logic and the already-obsolete Universal Analytics inheritance. A container meant to scale can’t carry invisible technical debt; every extra variable is more surface area for the next problem to hide in.
The cause of a data discrepancy is almost never a single one once a container has been in production for years. Hunting for "the" bug instead of auditing 100% of the container is the most common way to fix one symptom and leave the other two intact.
FAQ
Why not just detect these three causes with a simple before/after number comparison?
Because the three overlapped partially — a session could be excluded by two of the three at once. Comparing only the aggregate total doesn’t let you isolate how much each one contributes; each system’s logic has to be audited separately.
Was this process documented for reuse on other containers?
Yes, that was the goal from the start — the audit method (tracing dependencies before moving anything) was designed specifically so future migrations wouldn’t have to reinvent the process from zero.