Skip to main content

How we accidentally poisoned our sister brand's ad campaigns with a rogue tracking tag

·954 words·5 mins
Marketing Tech Analytics Hubspot

I was sitting with a lukewarm cup of coffee on a Tuesday morning, running what I figured would be a boring, 10-minute tag audit on our main e-commerce site. Then Google Tag Assistant flagged something that made no sense. Alongside our own Google Ads tag, a second tag with the ID AW-987654321 was firing on every single page view.

That second ID belonged to our sister brand. They are a smaller, lower-priority setup under our corporate umbrella, selling a very similar catalog of products. I hopped over to their domain, loaded their home page, and watched the exact reverse happen: our primary brand’s tag, AW-123456789, was firing over there. Visitors looking at our high-margin main line were being quietly tagged for our cheaper secondary line, and vice versa. I had that familiar cold-sweat moment where you assume your browser cache is lying to you; I cleared everything, opened 3 incognito windows, and watched the exact same thing happen.

We had a silent, cross-domain audience leak, and we had no idea how long it had been running. Here is how we found it, why it happened, and the trade-off you make when you let marketing platforms manage your tracking code.

The reality of the audience overlap
#

Illustration for The reality of the audience overlap Our immediate reaction was to panic and check our Google Ads conversion dashboards. If we had been double-reporting purchases across both accounts, we had probably spent weeks optimizing for fake conversions and inflated performance data. Luckily, we dodged that bullet: the cross-firing tags were only executing gtag('config', 'AW-XXXXXXXXX') pageviews and remarketing events. The distinct conversion labels we tied to our checkout success pages remained isolated on their respective domains.

But the problem was still pretty bad. Modern ad campaigns rely heavily on algorithmic targeting. When you run Google Performance Max (PMax) campaigns, Google uses your remarketing lists and search-to-pageview user behaviors as “audience signals” to decide who to bid on next. By blending these 2 audiences without realizing it, we were feeding slightly skewed signals to our bidding models, subtly drifting them off course. A real pain in the ass to diagnose after the fact, because the damage shows up as slowly declining efficiency rather than a sudden, obvious error.

Chasing ghosts in Google Tag Manager
#

Illustration for Chasing ghosts in Google Tag Manager Naturally, we assumed we had messed up our Google Tag Manager (GTM) containers. It is incredibly easy to copy-paste the wrong variables or link the wrong container when you are switching between tabs for multiple brand properties.

I opened our GTM workspace for the primary brand, filtered for any tag containing the rogue ID 987654321, and found absolutely nothing. I checked our GTM container injection script in the website source code; the container ID matched our production environment GTM-KXYZ123 exactly:

<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-KXYZ123');</script>
<!-- End Google Tag Manager -->

Next, I suspected a hardcoded layout file—maybe some ancient template had been cloned from one brand repository to another. I ran a global search across our Git repository for both tag IDs. Zero matches.

We spent 2 hours in growing frustration, asking stupid questions and blaming everything from browser extensions to CDN caching. If GTM did not contain the script, and our raw source code did not reference the rogue ID, how was the browser loading it?

Finding the culprit in the network panel
#

Illustration for Finding the culprit in the network panel To find the source, we had to stop looking at our code and start tracing the request initiator chain in Chrome DevTools.

I opened the Network tab, filtered by collect?v=2 and pagead, and reloaded the page. There they were: 2 separate outgoing requests to Google’s servers.

Request URL: https://www.google.com/pagead/1p-conversion/987654321/?random=1710000000...
Request URL: https://www.google.com/pagead/1p-conversion/123456789/?random=1710000000...

I right-clicked the rogue 987654321 request and selected Initiator. The dependency graph pointed directly to a third-party script:

(index) -> js.hs-scripts.com/44556677.js -> js.hs-analytics.net/analytics/1710000/44556677.js

44556677.js was our shared HubSpot tracking script.

Because we operate both sites under a single corporate umbrella, we had set up a multi-brand HubSpot instance. To simplify our dashboard reporting, we had gone into Settings > Integrations > Connected Accounts and linked both the primary brand’s Google Ads account and the sister brand’s Google Ads account to the same hub. It seemed like a perfectly logical setup at the time.

What we did not realize is that HubSpot’s native Google Ads integration defaults to auto-injecting the connected account’s remarketing pixel into every single page where the HubSpot tracking script is present. Because both websites loaded the same corporate HubSpot script to manage our contact forms and chat, HubSpot was helpfully auto-injecting both Google Ads pixels onto both domains.

We had not written a single line of bad code; a SaaS tool’s default, out-of-the-box behavior had quietly bypassed our entire engineering workflow.

The trade-off operators need to watch out for
#

Illustration for The trade-off operators need to watch out for If you run multiple sites, partner networks, or sister brands, you need to look closely at this exact compromise.

“One-click” CRM integrations are built for simplicity, not isolation. They want to make your life easier by automating pixel deployment, and for many teams, having a unified audience pool across similar brands is actually a benefit. It saves you from maintaining complex GTM firing rules and ensures you do not miss tracking visitors on secondary properties.

But if your brands require strict audience separation—perhaps because they target different customer segments, run distinct pricing tiers, or feed highly sensitive machine-learning bid strategies—this automation is a silent risk.

Your tag manager is not the only system writing to your users’ browsers. If you value absolute data hygiene over configuration speed, you have to audit your third-party integrations. Inspect your network payloads, map your script initiators, and make sure you aren’t letting your CRM make tracking decisions on autopilot unless you are entirely comfortable with the cross-pollination.

Related

When Plesk traffic doesn't match Analytics: finding a WordPress compromise
·1395 words·7 mins
Tech Security WordPress DevOps
The number that started it # Plesk was showing 7294.2 MB/month of traffic for one of our internal WordPress sites — which would have made it one of the busiest domains on the server, except Google Analytics and Cloudflare both said the site was nearly dead. A handful of real visits, nothing more.
Your .gitignore won't save you from AI coding assistants
·1587 words·8 mins
Tech AI Security
AI coding agents are runtimes with root-level terminal access. If you rely on file-level ignore lists to protect your secrets, you are one bad stack trace away from leaking live production credentials to third-party model providers.
Marketing first principles I tell my mentees before they touch a platform
·869 words·5 mins
Marketing Strategy Brand Building Leadership
After years of watching mentees chase platforms and tactics, the real work is always the same: strip the problem back to the human logic underneath. These are the principles I lead with, why they resist them, and where I have watched the gap cost people.