Your COGS field is empty

That has got nothing to do with tracking, but it has got everything to do with optimization

Hellooo,

I sat in on three calls with a US Shopify Plus brand over the last few weeks. And I want to tell you what happened, because it has nothing to do with what you think it has to do with.

This brand had everything.

Server-side tracking tool. Attribution tool. Email platform. SMS platform. Product analytics platform. ERP. Returns app. Consent app.

Eight tools. A stack that would make most ecom teams jealous.

But the problem was they could not send a single signal that actually mattered to them.

Here's what they wanted

Three things. All reasonable.

  • One: stop telling Meta "purchase" and start telling it as "profitable purchase."

  • Two: stop acquiring customers who return everything.

  • Three: see one unified customer profile instead of six half-profiles.

Every one of these is a solved problem technically. Every one of them was blocked.

Not by the tools, But By an empty field

We opened their Shopify product page on the call. Scrolled to the cost per item field.

We saw the blank.

Nobody had ever filled it in. The real COGS lived in NetSuite, but NetSuite only registers margin after payments are applied, which is days after the order. And their actual cost per unit swings with tariffs and PO batches anyway.

So here's the situation: a brand that desperately wants Meta to optimize for profit, sitting on an ERP full of profit data, and there is no path from that data to the ad platform in a timeframe the algorithm can use.

You cannot send a signal your business has not written down somewhere a system can read it.

That's it. That's the whole thing.

Their fix, by the way, was not heroic. Their ops lead pulled the lowest wholesale tier price from their B2B catalog and proposed using it as a baseline cost. Not exact. Directionally right. Automate it across the catalog, and suddenly a "high margin purchase" event exists where nothing existed before.

Ninety percent right and flowing beats one hundred percent right and stuck in NetSuite.

Then we got to returns

Returns are creeping up month over month. And he asked the obvious question: can you tell Meta to stop finding people who return things?

We opened Shopify orders. Filtered by return status. No tags. No flags. Nothing marking a returned order.

Because their returns app owns that data. Shopify never gets told.

So the return event that everyone assumes is sitting in Shopify waiting to be sent?

It does not exist. It lives inside a third-party app that nobody thought to connect, and the fix was a webhook conversation with the returns vendor that had never happened in years of running the store.

And here is the part almost nobody gets right

Even once you have return data, you cannot send it as a conversion event.

Think about the timing.

A purchase fires the second it happens. Ad platforms want it immediately. That's the deal.

A return happens three weeks later. There is no way to retroactively tell Meta "remember that purchase event? Bad one."

So returns are not a signal. Returns are an audience.

You collect the profiles of people who returned, build a cohort, push it to your ad platforms, and set it to permanent exclusion. Then you seed lookalikes from the people who kept the product.

Marketers who try to force returns through the event layer get nothing and conclude it doesn't work.

The third one: everyone had a profile, nobody had the customer

Their product analytics tool showed beautiful user journeys - pages, clicks, videos watched, UTMs, city, device.

User ID field: blank.

It only populated when someone logged in or placed an order. Everyone before that was a ghost with a rich behavioural history and no name.

Meanwhile Shopify had its own ID. The ERP had another. The email tool had another. Four systems, four identities, one actual human, zero stitching.

The unified customer profile everyone assumes they have is usually four disconnected profiles wearing a trench coat.

Looks like three separate problems, but really it is just one

None of these tools own identity. They each hold one fragment and hand it downstream. So there is no layer where cost data, return data, browsing behaviour, and CRM data can meet the same person.

That layer is what CustomerLabs is.

Concretely, for this stack:

  • A first-party domain cookie assigned server-side, not browser-side, so it survives ad blockers, ITP, and AI browsers, because it comes from your DNS, not a third party's script

  • A profile that starts on the anonymous first visit and keeps appending behaviour, so when they reveal themselves on day 200 the entire journey is already attached

  • Shopify's customer events sandbox for checkout, so checkout extensibility isn't a black hole

  • Profit-tier and category purchase events built off a COGS field, sent to Meta, Google, TikTok as distinct signals, not one generic Purchase

  • Returner cohorts pushed as permanent exclusion audiences, with lookalikes seeded from keepers

  • Webhook destinations for tools we don't natively integrate with, so an SMS platform or a returns app can still be part of the loop

  • Consent state pulled in, so profiles that declined simply don't get activated downstream

One identity layer. Every tool downstream finally talking about the same person.

The uncomfortable question

Go open a product in your Shopify admin right now. Scroll to cost per item.

Is there a number in it?

If not, no amount of CAPI, attribution software, or algorithm whispering is going to make your ad platform optimize for profit. It cannot optimize for something you have not written down.

Start there. Then come talk to us about the rest.

Book a 1:1, we'll audit which signals you're structurally unable to send Or start the 14-day trial and see your own event accuracy first

Reply

or to participate.