The Reluctant Guide to Shopify Migrations

Act V: The Appearance of Completion

The Onion (Which Is To Say, The Tracking Stack)

Legal wanted Consent Mode v2, and said so in a meeting, and was right to. Marketing wanted the pixels firing by the campaign launch, and said so in the same meeting, and was also right. Engineering wanted a spec before touching anything, which was the most reasonable position in the room and the one most easily talked out of, because the campaign had a date and the spec did not. So the consent setup got built the way most consent setups get built: by committee, in pieces, each party solving the slice of the problem it could see from where it sat. The banner went up. The pixels fired. The dashboard filled with numbers. Everyone went back to their actual jobs.

Nobody, at any point, owned the question of whether the consent log was evidentiary—whether, if a regulator or a customer ever asked the brand to reconstruct exactly what a given person had agreed to, the system could answer. That question didn’t belong to anyone, because it lived in the seam between three teams, and seams don’t show up on dashboards. The thing looked complete from the outside. It would keep looking complete right up until the one day it mattered, and on that day the gap would not be a surprise so much as a thing that had been there the whole time, patiently, waiting to be looked at.

A halved onion with neat concentric rings visible in cross-section, but with a small dark hollow at the center where the core should be.
Looked whole from the outside. Almost always does.

That gap is invisible until it isn’t.


Think of your tracking stack as an onion. We mean this more literally than the metaphor usually gets used, so bear with the vegetable for a moment, because it does real work. The outer layer is the part everyone sees and the part everyone mistakes for the whole: a cookie banner, a couple of pixels, maybe a Google Analytics integration that somebody wired up and screenshotted for a status update. Peel that back and there is a second layer underneath, governing how the consent signals actually travel to the places they’re supposed to go. Peel that back and there is a third layer at the core, governing how much of the data survives the trip intact. Three layers. Each one wraps the one beneath it. Each one is built with different tools, owned by different people, and—this is the part that ruins migrations—each one quietly decides what is even possible at the layer inside it.

Most brands stop at the skin. They build the outer layer, confirm the banner appears and the numbers move, and conclude the onion is whole. Then they spend the next year wondering why the inside doesn’t hold up—why the match rates are soft, why the conversion data feels directionally true but not quite trustworthy, why an audit of the thing surfaces problems in rooms nobody remembers building.

The mistake is almost never which tool they picked at a given layer. The tools are mostly fine; the vendors are mostly competent; the documentation mostly exists. The mistake is starting from the wrong layer entirely—usually the core, sometimes the middle—and treating consent, the outermost and most foundational ring, as a checkbox someone else handled. You cannot enrich your way out of a broken consent layer. You can only enrich your way deeper into the problem, which we will get to, because it is the single most expensive way a tracking stack goes wrong.

So we are going to peel the onion in the only order that works: from the outside in. Skin first.


The outermost layer is consent—what the user actually agreed to share—and on Shopify its foundation is the Customer Privacy API. Everything downstream has to talk to this. It is the bouncer at the door; every signal that reaches a pixel or a server is one this layer either waved through or turned away.

The API handles four consent fields: analytics, marketing, preferences, and sale_of_data. A customer accepts or declines your banner, those fields get set, and the well-behaved tools downstream are supposed to honor them. For a great many Shopify stores this is genuinely enough—single market, ordinary consent obligations, a standard pixel setup. The native API does the job and you can stop reading this section.

The gap opens when Google Consent Mode v2 walks in. CMv2 wants six separate consent signals, and the mapping from Shopify’s four fields is not one-to-one. Shopify’s single marketing field has to fan out into three distinct CMv2 parameters—ad_storage, ads_user_data, and ads_personalization. A consent management platform sitting on top can do that remapping. But here is the catch, and it is the kind of catch that is structural rather than fixable-by-trying-harder: when the CMP remaps those granular signals down into Shopify’s model, Shopify’s own consent log records the upstream Shopify field, not the three CMv2 signals the user was actually asked about. The log remembers the translation, not the original.

Which means that on the day a customer files a data subject access request, or a regulator asks you to demonstrate precisely what someone consented to, Shopify’s log cannot give you that granularity. It was never holding it. It held the four-field summary, faithfully, the whole time—and the four-field summary is not the evidence you were quietly assuming you had. The brands that operate across GDPR markets, or run CMv2, or carry any granular consent obligation, want a dedicated CMP—iubenda, Cookiebot, OneTrust—sitting on top of the Customer Privacy API and keeping its own audit trail. The CMP doesn’t replace the API. It feeds it, and it remembers what the API forgets.

This layer has an ownership problem baked into it, and it is exactly the one from the meeting at the top of this chapter. Legal asks for CMv2. Marketing asks for the pixels. Engineering asks for the spec. The setup gets assembled by committee, the evidentiary question falls into the seam between them, and nobody owns the log until the day the log is the only thing anyone wants.


Peel the skin and you reach delivery: how the consent-gated events actually travel from the banner to your tracking destinations. Two roads. Shopify Pixels, or a tag container like Google Tag Manager.

Shopify Pixels handle the consent gating natively. A user declines, the pixel doesn’t fire, and you didn’t have to wire anything to make that true. Low maintenance, correct by default, and the right call for any team without a mature GTM practice. GTM buys you flexibility—conditional triggers, third-party scripts, tools with no native Pixel integration—and the price of that flexibility is a new place where the consent signal can break silently. A GTM trigger that doesn’t correctly read from the Customer Privacy API will fire its events regardless of what the user consented to. The events land in your destination platforms. The dashboards fill. Everything looks like it is working. And you are out of compliance, and there is nothing on the surface to tell you so.

We have watched this happen, on migration after migration, and it almost always wears the same costume. A GTM container comes over from the previous platform as-is—ported wholesale, because it worked there and porting it was one fewer thing to rebuild. The team knew GTM cold. They’d run it for years. What they hadn’t run was Shopify’s consent model, which the old platform didn’t have, so the container arrived fluent in the old world’s grammar and mute in the new one’s. It fired correctly. It just wasn’t wired to the Customer Privacy API at all, and nothing—not the dashboards, not the Pixel Helper, not a single visible symptom—surfaced the gap until somebody audited the consent flow directly and found it.

(Marketing Lead Who Was Told The Tracking Is Set Up: this is the paragraph for you. Somebody competent told you the tracking is set up, and they were not lying—from where they stood, it is. The events are arriving. The question is whether they’re arriving gated, and that question cannot be answered from the dashboard you’ve been looking at. It can only be answered by someone walking the consent path end to end with a real banner and real choices. If that walk has not happened, the tracking is not set up. It is firing, which is a different and more dangerous thing.)

For most mid-market brands the right shape is Shopify Pixels for the standard events and GTM only for the exceptions that genuinely need it. GTM-only earns its keep when you have mature container governance and a stack of custom third-party tags with no native support. Reaching for GTM because it’s the tool you already know is not, by itself, a good enough reason—not against the compliance surface area it quietly hands you.


Peel the delivery layer and you reach the core, and at the core is a constraint that surprises every engineering team exactly once, because it is structural and there is no arguing with it. Shopify pixels run inside a sandboxed iframe with no access to window.document.

Sit with that, because the consequences are larger than they first appear. Shopify pixels cannot scrape the DOM. They cannot read a customer’s email, their phone number, their customer ID, or anything else that isn’t explicitly handed to them through Shopify’s Web Pixels API. The whole category of traditional pixel libraries—the ones that assume they can reach into the page and lift out whatever they need—simply does not function in here. And if you want first-party data like email or customer ID attached to your events, which you almost always do, because that is what produces meaningful match rates over at Meta and Google and everywhere else, that data cannot come from a browser pixel. The sandbox forbids it. It has to come from somewhere else entirely.

Somewhere else is the enrichment layer. Tools like Elevar work at both ends of the journey: augmenting client-side events with additional attributes before they leave the browser, and firing parallel server-side hits straight to your destinations, bypassing the browser’s restrictions altogether. The two together produce higher match rates than either alone—browser context and server-side reliability, stitched into one signal. Not every brand needs this layer. If your paid-channel mix is modest and your match rates are already acceptable, enrichment buys you another vendor relationship and another data processing agreement in exchange for accuracy you weren’t short on. Know which problem you’re solving before you reach for it.

But here is the thing the onion is really trying to teach you, the lesson the whole vegetable exists to deliver, and it is counterintuitive enough that brands do the opposite by reflex. Enrichment added before the layers beneath it are correct does not fix anything. It makes things worse. A beautifully enriched event firing against a broken consent setup is not progress—it is a server-side hit now reaching your destination platforms regardless of what the user’s browser consented to, which means you have taken a compliance gap that was at least confined to the browser and given it a server-side bypass around the very consent state that was supposed to contain it. You have made the problem both bigger and harder to audit, and you did it while feeling productive. This is why the order is not a stylistic preference. Start at the core and you can pour effort into the innermost layer for a quarter and end up further from compliant than when you began.


Which is the discipline the whole onion comes down to, and it is less a tooling decision than a sequence. Consent, then delivery, then enrichment if you need it—verified end to end at each ring before you cut into the next. Every layer constrains what’s possible at the one inside it, so a team that starts in the middle is building on a foundation it never inspected, and the gaps end up in the rooms nobody thought to look in.

There are four questions, and they go in order, and they all come before any tool decision. What does our consent setup actually require—which jurisdictions, which signals, do we need CMv2, and where is the authoritative consent log being held? What is our event delivery path, and does it genuinely read from the Customer Privacy API, or has nobody checked? Do we have a signal-quality gap real enough to justify enrichment, or are our match rates already fine? And how will we test each layer end to end, with real consent flows and real orders, before anyone is allowed to call the setup done?

The brands that walk those questions in order tend to find something they didn’t expect, and it is worth saying plainly because it inverts where everyone instinctively looks first. Most teams that work through this properly find that the problem was never in the innermost layer. It was never the enrichment vendor, never the match rate, never the server-side configuration everyone wanted to blame. It was a consent signal that broke in transit two layers out, in a GTM container nobody had thought about since the migration, quietly firing ungated events into the world while the dashboards said everything was fine.

The onion looked whole from the skin. They almost always do. That is the entire reason this is a chapter and not a checklist—the surface of a tracking stack is engineered, by accident and by vendor incentive, to look finished. Shopify partially handles this, the way Shopify partially handles a great many things in this part of the book: it gives you a real consent API and a real native pixel and a real testing extension, and then it draws a line, and on the far side of that line is everything those tools quietly do not reach. Knowing where that line falls—layer by layer, signal by signal—is the work. It is not glamorous. It does not demo well. But it is the difference between a tracking stack you’ve peeled and one you’ve only photographed.

Start with the skin.