It was probably a developer, three years ago, and nobody reviewed it.
A client asked Marc Alexander what looked like a simple question. They had switched off their on-site experimentation platform, conversion had fallen, and they wanted to know what the switch-off had cost. A recommendation to drop the platform permanently was already being drafted.
Four things had changed inside eight days. A sale ended. There was a payment incident. A release went out. Then, last of the four, the platform was switched off.
More than 40% of the conversion decline had happened before the platform was touched. Checkout completion had collapsed two days earlier, on the day of the release, and never recovered. Engagement was flat throughout, either side of the switch.
Removing on-site experiences changes what visitors see, and that shows up in engagement. A sale ending doesn't. It changes whether people buy. So the read-out was almost certainly measuring the sale, and possibly the release, and blaming both on the platform.
Settling it needed four things: order mix (orders with discounted items against orders with none), cart abandonment, session duration by journey and page depth by journey. Not one of them existed.
No ecommerce event carried an item-level discount field, so discounted and full-price orders couldn't be separated. There was no cart view event, because the basket page sent no ecommerce data at all. Session duration and page depth were collected sitewide, but page type values differed between templates, so neither could be cut by journey.
A business was days away from a permanent platform decision on evidence that couldn't support one. Nothing was broken. Every tag fired. Consent was gated correctly. QA had come back clean.
The choice nobody remembers making.
At some point somebody wrote a page template and chose which fields it would send. That choice was made on a Thursday, under delivery pressure, by a developer who had never been told what the business would need to ask.
Nobody reviewed it, because it never failed. And it quietly fixed the limit of what that company could know about its own trading.
No amount of tag manager work rescues it. A container can rename, cast, enrich, suppress and route, but only data the page has already pushed. It can't carry a field the page never sent, construct a discount that isn't in the source object, or fire a basket event where no basket data exists.
So a dataLayer isn't a tracking artefact. It's a specification of the questions your business is allowed to ask. In most businesses it was written by accident, by people who were never told what it was for, and nobody in a commercial role has read it since.
The fault isn't the developer's. Nobody on the commercial side ever wrote down what the business would need to know. If you're accountable for trading performance and have never seen your own dataLayer, it's the most consequential document about your business that you've never read.
The cost is real. Every promotion you can't evaluate is margin given away without knowing whether it bought anything, and you'll run it again next quarter because you have no evidence not to.
Every media platform bidding without a pre-purchase value signal is optimising towards the wrong customers with real money. Price those two across a year against the cost of adding fields to a template, and it isn't close.
Once you see it, it's everywhere.
That business wasn't unusual. The same gap keeps turning up in different forms:
- No item-level discount or coupon. You can't tell whether a promotion drove extra orders or discounted orders that would have happened anyway.
- A basket page with no ecommerce data. You can't see who built a basket and left, what was in it or what it was worth, and abandonment audiences have nothing to draw on.
- Product prices with no top-level value. No step before purchase has a value, value-based bidding gets no pre-purchase signal, and no release can be judged in money.
- No payment attempt or outcome recorded. You can't tell declined customers from ones who chose to leave. With no attempts there's no denominator, so a failure rate can't exist even in principle.
- Price sent as text on one event and a number on another, same page, same product. Warehouse queries fail or silently drop rows, and dynamic remarketing can't read a price that arrives as a string.
- A list ID that's really the list's display name. Rename a merchandising list and its history splits in two.
- Page and site type values that differ between templates. Engagement is collected and can't be cut by journey. The most frustrating one, because the data is sitting right there.
The one Marc almost never finds is stock status at the moment of viewing: in stock, low stock or out of stock, per item, when the customer looked.
Without it, when conversion falls in a category, demand and availability look the same. Merchandising knows which sizes were out last Tuesday. It never reached the event. Did you lose the customer, or their size?
Nobody chose any of this. That's the point. It was never specified, so each template solved it locally, and every local answer was reasonable at the time.
Why it survives for years.
Two reasons, and they compound.
It never fails loudly. Broken tracking gets escalated within a day because a chart goes flat. A missing field never gets escalated. There's no error, no alert, nothing turns red. The question gets a vague answer once and stops being asked.
It always loses the queue. In the case above, the development team was at capacity on a replatform, so measurement work had been deferred behind it. That's exactly backwards, because the templates that send the dataLayer were the very things being rewritten.
Writing a correct push into a template someone is already building costs a fraction of retrofitting one that's been built, tested and signed off. The busiest moment is the cheapest one, and it's almost always the one that gets skipped.
The order almost everyone gets backwards.
The fix is a sequence, not a tool.
Start with the decisions your business makes on a cycle: promotional planning, range and buying, media allocation, platform investment. For each decision, write down the questions it turns on. For each question, list the fields needed to answer it at event level. Then design the schema. Then build the tags.
Done in that order, the dataLayer becomes a contract between the business and the site that a commercial director can read, because it's written in questions rather than parameters. Done the usual way, from the tool backwards, you get data that answers whatever the tool suggested and none of what the business asks.
It needs one named owner who isn't the person shipping the feature, and it needs to be part of the definition of done for every template change. Without both it never ships, because it's nobody's feature and has no launch date.
Back to the decision.
That client didn't drop the platform on the strength of the read-out. Not because the data eventually answered the question, but because the sequence of events was enough to show it couldn't.
Most businesses sit there: reasoning around a gap and hoping the reasoning holds, until the decision is expensive or the person reasoning isn't in the room.
The uncomfortable part is that fixing it doesn't fix the past. Collection only works forwards. An event that was never sent can't be recovered, at any price, by anyone. The gap you leave open this quarter is a hole in next year's evidence, and it'll still be there when somebody senior finally asks.
So the honest answer to a question your data can't answer today isn't "give us two weeks". It's "ask again in a year".
Marc, a GA4 consultant, specifies measurement for ecommerce businesses: what the pages must send, in what order, and which commercial questions that makes answerable. If you'd like to start with the questions your leadership actually asks, expert GA4 setup is where that work sits.