You set up the TikTok Pixel in GTM with the official TikTok template from the Community Template Gallery, your Pixel ID, and one tag per standard event (ViewContent, AddToCart, InitiateCheckout, CompletePayment) carrying value, currency, and content_id. That part takes 20 minutes.
The part that takes longer is consent. Google Consent Mode v2 doesn't control the TikTok Pixel. If your banner talks to GTM only through Consent Mode, TikTok is almost certainly firing for users who clicked "Reject all". This guide covers both halves: the build, and the gate you have to add yourself.
- Use the TikTok Pixel template published by TikTok in the GTM Community Template Gallery. Don't paste the base code into a Custom HTML tag.
- Purchases go through
CompletePaymentwithvalue,currency, andcontent_id. Without value and currency, value-based optimization has nothing to work with. - Consent Mode v2 signals adjust Google tags only. TikTok ignores them, so you need "Require additional consent for tag to fire" with
ad_storageon every TikTok tag. - The pixel writes
_ttpand_tt_enable_cookie. Neither should exist after a user denies consent. That's your 90-second test. - If you add the Events API later, send the same
event_idfrom browser and server, or TikTok counts every order twice.
Why TikTok sits outside Consent Mode
Consent Mode v2 is a Google protocol. When your CMP sets ad_storage to denied, Google tags (GA4, Google Ads, Floodlight) read that state and change their own behavior: no cookies, a cookieless ping instead. The tag is built to listen.
TikTok's pixel isn't a Google tag. It doesn't read gtag('consent', ...) at all. It has no cookieless mode that GTM can switch on for you. So when GTM fires it, it loads analytics.tiktok.com, writes its cookies, and sends the event. Every time.
I'll be blunt: a container where every non-Google tag fires on All Pages, and the only consent logic is the Consent Mode default command, isn't a consent setup. It's a Google setup with a banner on top.
This is the same gap I described for the LinkedIn Insight Tag in GTM. TikTok is worse in one way: it tends to get added fast, by a social media freelancer, during a campaign launch, with nobody checking the consent settings.
Not sure which of your tags ignore consent? The Free GTM Audit lists every tag in the container and flags the ones with no consent requirement. About 10 minutes, no signup.
What you need before you open GTM
Four things. Get them first, or you'll be clicking between tabs for an hour.
- Pixel ID. In TikTok Ads Manager, go to Tools, then Events, then Web Events. The ID is a string of 20 uppercase letters and digits, something like
C4ABCD1234EFGH5678IJ. - A data layer with ecommerce data. If your store already pushes GA4 events (
view_item,add_to_cart,purchase), you're 80% done. If not, start with the GA4 data layer guide. - A CMP that updates consent in GTM. Cookiebot, CookieYes, Usercentrics, Cookie Banner Pro, any of them, as long as it sets the consent state before tags evaluate.
- The TikTok Pixel Helper Chrome extension, for testing.
One decision to make now: does content_id in TikTok match the product ID in your catalog feed? If you run Video Shopping Ads or catalog retargeting, it must. A pixel sending SKUs while the feed uses WooCommerce post IDs gives you a 0% match rate and catalog ads that never deliver.
TikTok Pixel GTM setup, step by step
Here's the base build. It's the boring part and it should stay boring.
- In GTM, go to Tags, then New, then Tag Configuration, then Discover more tag types in the Community Template Gallery.
- Search for "TikTok Pixel" and pick the one published by TikTok. Check the publisher line. There are lookalikes.
- Click Add to workspace and accept the permissions.
- Enter your Pixel ID.
- For the base tag, choose the page view event (the template's default) and trigger it on Initialization - All Pages, not Consent Initialization.
- Open Advanced Settings, then Consent Settings, and set the consent requirement (next section). Don't skip this to "test first". Tests become production.
- Preview, check with the Pixel Helper, publish.
The template also handles Advanced Matching: you can pass a hashed email or phone number. In the EU, treat that as personal data under the same consent as everything else. I wouldn't turn it on until the consent gate is proven to work.
The standard events and their parameters
This is where most TikTok setups lose money quietly. The event fires, Ads Manager shows a green dot, and nobody notices the value field is empty.
| TikTok event | When it fires | Parameters that matter | Maps from GA4 event |
|---|---|---|---|
ViewContent |
Product page view | content_id, content_type, value, currency |
view_item |
AddToCart |
Item added to cart | content_id, quantity, value, currency |
add_to_cart |
InitiateCheckout |
Checkout started | contents, value, currency |
begin_checkout |
AddPaymentInfo |
Payment method chosen | value, currency |
add_payment_info |
CompletePayment |
Order confirmed | contents, value, currency, content_type |
purchase |
SubmitForm |
Lead form sent | none required | generate_lead |
Three rules I apply to every build:
currencyis an ISO code.EUR,PLN,CZK. Not "€", not "zł". TikTok drops or misreads anything else.valueis a number. Not"1 249,00 zł"as a string. Format it in the data layer or in a Custom JavaScript variable before it reaches the tag.content_typeisproductorproduct_group. Pick one per site and stick to it.
For CompletePayment I map straight from the GA4 purchase push. The contents array is built from the GA4 items array with a small Custom JavaScript variable:
function() {
var items = {{DLV - ecommerce.items}} || [];
return items.map(function(item) {
return {
content_id: String(item.item_id),
content_name: item.item_name,
quantity: Number(item.quantity) || 1,
price: Number(item.price) || 0
};
});
}
Then the tag gets contents = that variable, value = {{DLV - ecommerce.value}}, currency = {{DLV - ecommerce.currency}}. Trigger: a Custom Event trigger on purchase. If you've never built a Data Layer Variable, it's Variables, then New, then Data Layer Variable, with the name ecommerce.items.
Gating TikTok for EU consent
There are two clean ways to do it. I use the first one by default.
Option 1: Require additional consent (my default)
On every TikTok tag, base and events:
- Open the tag, then Advanced Settings, then Consent Settings.
- Select Require additional consent for tag to fire.
- Add
ad_storage, plusad_user_data, since the pixel sends user-level data to an ad platform. - Save, then repeat for every TikTok tag, all of them.
GTM now holds the tag until those consent types are granted. If the user accepts on the second pageview, the tag fires from that point on. If they never accept, it never fires. It works with any CMP that updates GTM consent state, and it's visible in the tag list, which matters when an auditor asks.
Option 2: Trigger conditions or CMP events
The older approach: your CMP pushes an event like cookie_consent_marketing, and you trigger TikTok on that event, or add a condition Marketing Consent equals granted to the trigger.
It works. It's also fragile. If the CMP loads slowly, the condition evaluates before consent is known, and depending on how it's written, you either lose the first pageview or fire without consent. Consent timing is where I find most leaks. It's the reason I built the Universal Consent Adapter.
TikTok also has its own consent calls (ttq.holdConsent(), ttq.grantConsent(), ttq.revokeConsent()). They're useful on sites without GTM. Inside GTM, I'd rather have one consent mechanism for the whole container than a TikTok-specific one.
The 90-second test
Configuration proves nothing. Test it:
- Open the site in a fresh incognito window.
- Click Reject all in the banner.
- Open DevTools, then Application, then Cookies, and look for
_ttpand_tt_enable_cookie. - In the Network tab, filter for
tiktok. There should be zero requests toanalytics.tiktok.com. - Accept consent, reload, and check that both appear.
If the cookies show up after a rejection, the setup is decorative. The Consent Mode checklist has the same test for Google tags, so you can run both in one sitting.
Weronika's store: two problems in one container
Weronika runs a cosmetics store in Kraków, about 620 orders a month, roughly 30% of traffic from TikTok. Her freelancer installed the pixel in March 2026. In June she asked me why TikTok reported 1,010 CompletePayment events for a month with 640 actual orders.
The container had two TikTok setups. The freelancer's Custom HTML base code, pasted from Ads Manager, firing on All Pages.
And a newer template tag added by an agency, also firing CompletePayment on the thank-you page. Some orders were counted by both. Neither had any consent setting.
The fix took an afternoon:
- Deleted the Custom HTML tag and kept the template.
- Added
ad_storageandad_user_dataas required consent to all five TikTok tags. - Moved
CompletePaymentfrom a Page View trigger on/order-received/to thepurchasedata layer event, so a refresh of the thank-you page stops sending a second purchase.
July: 655 orders, 431 CompletePayment events. Lower than before, and correct.
About 66% of buyers accept marketing cookies on her banner, which matches. Her ROAS in TikTok dropped on paper. Her actual margin didn't change at all. It's a hard conversation, and it's the one an honest setup forces.
The Events API and event_id deduplication
The TikTok Events API is the server-side half: your server sends conversions directly to TikTok, so ad blockers and Safari's tracking limits don't eat them. Same idea as the Meta Conversions API.
Two things matter here.
Deduplication needs a shared event_id. If the browser pixel and the server both send CompletePayment for the same order, TikTok counts it once only if both carry the same event_id.
I use the order number, prefixed: order_48213. Set it in the template's event ID field and in the server payload. No shared ID, double counting. Guaranteed.
Server-side doesn't create consent. If Kamil, a shopper in Gdańsk, rejected marketing cookies, sending his purchase to TikTok from your server instead of his browser is the same processing, just harder to see. Your server-side TikTok tag needs the same consent condition as the browser one. If you're running server-side GTM, pass consent state through to the server container and check it there.
Is the Events API worth it? For stores with real TikTok spend, above maybe €3,000 a month, usually yes. Below that, I'd fix the browser setup first. A clean pixel beats a messy pixel plus a messy server feed.
Frequently asked questions
Does Google Consent Mode v2 control the TikTok Pixel? No. Consent Mode signals are read by Google tags only. The TikTok Pixel ignores them, so you have to block it in GTM with "Require additional consent for tag to fire" or with consent-based triggers.
Which TikTok event should I use for purchases?
Use CompletePayment with value, currency, and contents (or content_id). Fire it from the purchase data layer event, not from a thank-you page URL, so a page refresh doesn't send it twice.
Should I use the TikTok template or Custom HTML in GTM? The template published by TikTok in the Community Template Gallery. It's sandboxed, has fields for every parameter and the event ID, and supports GTM consent settings without extra code. Custom HTML works, but it's harder to audit and easy to duplicate.
What cookies does the TikTok Pixel set?
The main first-party ones are _ttp and _tt_enable_cookie. In the EU both need marketing consent before they're written. If you see them after rejecting consent in incognito, your gate isn't working.
Do I need the TikTok Events API?
If TikTok is a meaningful sales channel, yes, because browser tracking loses conversions to ad blockers and browser limits. Send the same event_id from browser and server for deduplication, and apply the same consent rules on the server.
Why does TikTok report more purchases than my store?
The usual causes are a duplicate pixel (Custom HTML plus template), a purchase tag on a thank-you page that fires on every refresh, or browser and Events API sending the same order without a shared event_id. TikTok's attribution windows also count view-through conversions, which your store doesn't.
Next steps
Open your GTM container and filter tags by "TikTok". Count them. If there's a Custom HTML tag and a template tag, you've found your first problem. If none of them show a consent requirement in the tag list, you've found your second.
Then run the 90-second test. Incognito, Reject all, look for _ttp. It tells you more than any dashboard will.
If you'd rather have someone check the whole container, every vendor and not just TikTok, the Free GTM Audit flags tags that fire without consent. And if you want that checked continuously instead of once, that's what GTM monitoring does, from €390/month, written report, no calls.
Sources and further reading - TikTok Pixel overview (TikTok Business Help Center) - TikTok Events API (TikTok for Developers) - Consent settings in Google Tag Manager (Google)
Is your TikTok Pixel firing before consent?
The Free GTM Audit checks which tags in your container respect consent and which fire anyway. Enter a URL, get a report in about 10 minutes.
Start Free GTM Audit