Tracking rarely breaks loudly. There’s no error message, no alert, no red banner. Conversions just get a little lower, or a little weirder, and you spend two weeks blaming the creative.
Most of the accounts I’ve looked at had something off. Not always a disaster. But almost always something.
And it matters more than it used to. If you’re sending profit or closed deals back to the platforms, like I talk about in Platform ROAS isn’t revenue, all of that sits on top of tracking. If the tracking is wrong, the platforms are learning from the wrong data.
The quiet ways tracking breaks
The source never gets stored. This is the big one. Someone lands from an ad with UTMs and a click ID in the URL, then browses to another page and converts there. The new page has no UTMs, nothing saved them, and the conversion shows up as direct or with no source at all. The landing page knew exactly where they came from. Nobody wrote it down.
There’s more than one pixel. Someone added a pixel through a Shopify app. Someone else added it in Tag Manager. An old agency hard-coded one in the theme two years ago. Now the same purchase fires two or three times, or fires to two different pixel IDs, and the platform can’t tell they’re the same sale.
Events fire at the wrong time. The purchase event fires when the checkout page loads instead of when the order goes through. The lead event fires when someone clicks the submit button, even if the form errors out. You get conversions that never happened.
Browser and server events don’t match up. You run the pixel and server-side events together, which is good. But Meta only treats them as one event if both send the same event ID and event name. If one side is missing the ID, or one sends “order_123” and the other sends “123,” every purchase counts twice.
A site update moved things. The thank-you page has a new URL. A new checkout, subscription app, or form tool took over, and nobody wired the events back up.
Values are wrong. The purchase fires with a value of 0, the wrong currency, or with tax and shipping included when it shouldn’t be.
The consent banner blocks more than you think. A cookie banner set up a little too strictly can quietly drop a big share of your conversions.
The ten-minute check
Grab a coffee and do this on your own site:
- Click your own ad, or add fake UTMs to your URL. Something like
?utm_source=test&utm_campaign=pixel-check. Then browse to a different page before converting. - Convert. Place a test order or submit the form. Then check your store or CRM: did the source come through on that order or lead? If it says direct or blank, your UTMs aren’t being stored.
- Open the platform test tools while you do it. Meta has Test Events in Events Manager. Google has Tag Assistant. GA4 has DebugView. Each one shows events as they fire.
- Count the purchase or lead events. You want exactly one per platform. Two means duplication. Zero means it’s broken. If you see two different pixel IDs, you have more than one pixel installed.
- Check when it fired. It should fire after the order or form actually goes through, not on page load or button click.
- Check the value. Does it match the order total you expect, in the right currency?
- Check deduplication in Meta. In Events Manager, open the purchase event and look at how much of it is being deduplicated between browser and server.
- Compare a week of data. Pull last week’s orders or deals from your store or CRM and compare them to what each platform reported. A small gap is normal. A big gap in either direction needs a look.
The fix for disappearing UTMs
You need a small script that runs on every page. When someone lands with UTMs or click IDs in the URL, it saves them in the browser. When they convert later, on any page, it fills those values into the form or order.
Here’s the basic idea:
<script>
(function () {
var KEYS = ["utm_source", "utm_medium", "utm_campaign", "utm_term", "utm_content",
"gclid", "gbraid", "wbraid", "fbclid", "msclkid"];
var params = new URLSearchParams(location.search);
var found = {};
KEYS.forEach(function (k) { if (params.get(k)) found[k] = params.get(k); });
try {
if (Object.keys(found).length) {
found.landing_page = location.pathname;
found.captured_at = new Date().toISOString();
// keep the first touch, always update the last touch
if (!localStorage.getItem("first_touch")) localStorage.setItem("first_touch", JSON.stringify(found));
localStorage.setItem("last_touch", JSON.stringify(found));
}
} catch (e) {}
// on submit, copy the stored values into hidden fields on the form
document.addEventListener("submit", function (e) {
var form = e.target;
["first_touch", "last_touch"].forEach(function (key) {
var saved;
try { saved = localStorage.getItem(key); } catch (err) {}
if (!saved) return;
var input = form.querySelector('input[name="' + key + '"]');
if (!input) {
input = document.createElement("input");
input.type = "hidden";
input.name = key;
form.appendChild(input);
}
input.value = saved;
});
}, true);
})();
</script>
A few notes:
- Make sure the values actually reach your CRM or store. The hidden fields only help if your form tool passes them along. Some form tools and embedded forms strip them, so test it end to end.
- Save the click ID with the lead. That
gclidis what lets you send a closed deal back to Google Ads later, within 90 days of the click. - Don’t rely on the browser alone for long sales cycles. Safari can clear data that scripts save after about 7 days. If people take longer than that to convert, store the source on your server the first time you see it.
Catching it before your numbers do
The ten-minute check is great once. The problem is that tracking breaks again the next time someone touches the site, installs an app, or changes a form. And if you manage more than a handful of sites, checking each one by hand doesn’t scale. I get into that in Running fifty client accounts.
The real fix is checking continuously: comparing what the platforms report against your actual orders every day, and flagging the moment they drift apart.
Clean tracking is also what everything else is built on. You can’t put a dollar value on micro-actions you aren’t capturing, and you can’t tell if the landing page is the problem if you don’t trust the conversion numbers.
Where Apello fits
Apello watches this for you. It edits and adds tags and events, keeps the source attached from the first click to the conversion, compares what each platform reports against your real orders, and flags drift as soon as it starts, with a plain explanation of what broke and a proposed fix.