Managing multiple ad pixels across Meta (Facebook), TikTok, and Pinterest can quickly become chaotic—especially when duplicate tags, inconsistent variables, or messy triggers bloat your GTM container. This article explains how to fire multiple pixel events from a single GTM Custom HTML tag, dynamically injecting platform-specific logic while maintaining speed, accuracy, and deduplication.
🧰 Prerequisites
Tool/Platform | Purpose |
---|---|
Google Tag Manager | Web container |
Meta Pixel ID | For Facebook/Instagram tracking |
TikTok Pixel ID | For TikTok Ads |
Pinterest Tag ID | For Pinterest Ads |
Consent Management | (Optional) For compliant firing logic |
✅ Use Case
Fire a unified Purchase
event to:
- Meta Pixel (and/or CAPI)
- TikTok Pixel
- Pinterest Tag
From one GTM tag after a successful checkout.
📦 Step 1: Push Unified DataLayer on Checkout
In success.twig
(or similar confirmation page):
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'purchase',
transaction_id: '{{ order_id }}',
value: {{ order_total }},
currency: '{{ currency }}',
content_ids: [{% for product in products %}'{{ product.product_id }}',{% endfor %}],
content_name: '{{ store_name }}',
content_type: 'product_group'
});
</script>
🌐 Step 2: Create a Single Custom HTML Tag in GTM
Tag Type: Custom HTML
Trigger: Custom Event = purchase
<script>
// ========== Meta Pixel ==========
fbq('track', 'Purchase', {
value: {{DL - value}},
currency: '{{DL - currency}}',
content_ids: {{DL - content_ids}},
content_type: '{{DL - content_type}}'
});
// ========== TikTok Pixel ==========
ttq.track('CompletePayment', {
contents: [{id: {{DL - content_ids}}, quantity: 1}],
value: {{DL - value}},
currency: '{{DL - currency}}'
});
// ========== Pinterest Tag ==========
pintrk('track', 'checkout', {
value: {{DL - value}},
order_id: '{{DL - transaction_id}}',
currency: '{{DL - currency}}'
});
</script>
Important:
- Use
{{DL - variable}}
to reference GTM variables tied to your Data Layer (e.g.,DLV - transaction_id
) - Make sure all variables are defined in GTM using Data Layer Variable type
🧪 Step 3: Load Pixel Base Codes Conditionally
In separate tags, add pixel base codes and trigger them on All Pages or via consent logic.
Meta Pixel Base
<script>
!function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);
t.async=!0;t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', 'YOUR_META_PIXEL_ID');
</script>
TikTok Pixel Base
<script>
!function (w, d, t) {
w.TiktokAnalyticsObject = t;
var ttq = w[t] = w[t] || [];
ttq.methods = ["page", "track", "identify", "instances", "debug", "on", "off", "once", "ready", "alias", "group", "enableCookie", "disableCookie"];
ttq.setAndDefer = function (t, e) { t[e] = function () { t.push([e].concat(Array.prototype.slice.call(arguments, 0))) } };
for (var i = 0; i < ttq.methods.length; i++) ttq.setAndDefer(ttq, ttq.methods[i]);
ttq.instance = function (t) {
var e = ttq._i[t] || [];
for (var n = 0; n < ttq.methods.length; n++
)ttq.setAndDefer(e, ttq.methods[n]);
return e
};
ttq.load = function (e, n) {
var i = "https://analytics.tiktok.com/i18n/pixel/events.js";
ttq._i = ttq._i || {};
ttq._i[e] = [];
ttq._i[e]._u = i;
ttq._t = ttq._t || {};
ttq._t[e] = +new Date;
ttq._o = ttq._o || {};
ttq._o[e] = n || {};
var o = document.createElement("script");
o.type = "text/javascript";
o.async = !0;
o.src = i + "?sdkid=" + e + "&lib=" + t;
var a = document.getElementsByTagName("script")[0];
a.parentNode.insertBefore(o, a)
};
ttq.load('YOUR_TIKTOK_PIXEL_ID');
ttq.page();
}(window, document, 'ttq');
</script>
Pinterest Base
<script>
!function(e){if(!window.pintrk){window.pintrk=function(){window.pintrk.queue.push(Array.prototype.slice.call(arguments))};var n=window.pintrk;n.queue=[],n.version="3.0";var t=document.createElement("script");t.async=!0,t.src=e;var r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r)}}("https://s.pinimg.com/ct/core.js");
pintrk('load', 'YOUR_PINTEREST_TAG_ID');
pintrk('page');
</script>
🔐 Step 4: Consent-Aware Triggering (Optional)
To comply with privacy laws, wrap your multi-pixel script logic in consent-based triggers:
<script>
if (window.consent_granted === true) {
// fire fbq, ttq, pintrk tracking
}
</script>
Or use GTM’s Consent Mode v2, enabling this tag only if "ad_storage"
and "analytics_storage"
are granted.
🧪 Step 5: QA Tools
Tool | Use Case |
---|---|
GTM Preview | Tag firing and variable check |
Meta Pixel Helper (Chrome) | Check Facebook events |
TikTok Pixel Helper | Confirm TikTok event transmission |
Pinterest Tag Helper | Validate Pinterest events |
Network tab (DevTools) | Verify request payloads |
🧠 Pro Tips
- Use a lookup table to manage different event names per platform (e.g.,
purchase
→CompletePayment
) - Consolidate content_ids, prices, and categories in a unified
ecommerce
object - For server-side GTM, replicate this logic as server events via API endpoints