utm.new
TikTok Ads logo
TikTok Ads
Paid social

TikTok Ads UTM parameters

TikTok's dynamic UTM macros wrap in double underscores — __CAMPAIGN_ID__, __AID__, __CID__ — and the naming is a trap: __AID__ is the ad group, not the ad, and __CID__ is the creative, not the campaign. ttclid is appended automatically for attribution (don't add it by hand). This page maps every macro to what it actually resolves to, gives a standards-only template that lands cleanly in GA4, and lists the ways the setup quietly breaks.

Updated
Recommended UTM template
Open in builder →
utm_sourcetiktok
utm_mediumcpc
utm_campaign__CAMPAIGN_NAME__
utm_id__CAMPAIGN_ID__
utm_term__CID_NAME__
utm_content__AID_NAME__

TikTok Ads tracks like the other paid-social platforms in shape — dynamic macros that the ad engine substitutes at click time — but two things trip people up specifically here. First, the macro syntax: double underscores at both ends, where one missing underscore silently breaks substitution. Second, and worse, the macro names don’t mean what they look like. __AID__ reads like “ad ID” but resolves to the ad group. __CID__ reads like “campaign ID” but resolves to the creative. Get those backwards and your reporting is mislabeled in a way no error message will warn you about.

This page maps every macro to what it actually resolves to, gives a standards-only template that lands cleanly in GA4, covers the ttclid story, and lists the ways the setup quietly goes wrong.

ParameterValueWhy
utm_sourcetiktokLowercase, no -ads suffix. GA4 splits TikTok / tiktok / tiktok-ads into separate rows.
utm_mediumcpcMatches GA4’s paid-channel regex so TikTok lands in Paid Social. paid-social also works but is less universal.
utm_campaign__CAMPAIGN_NAME__ or __CAMPAIGN_ID__Name is readable in reports; ID is rename-safe. Pick one and hold it for the campaign’s life.
utm_id__CAMPAIGN_ID__Always the numeric campaign ID. Powers GA4’s Campaign ID dimension and any cost-data import.
utm_term__CID_NAME__The creative name. TikTok has no keyword, so utm_term carries the asset you’re testing.
utm_content__AID_NAME__The ad group name — your audience/targeting layer.

This is the standards-only template the mini builder above hands you when you pick “TikTok Ads.” Six standard parameters, no custom fields, readable by every downstream tool:

utm_source=tiktok&utm_medium=cpc&utm_campaign=__CAMPAIGN_NAME__&utm_id=__CAMPAIGN_ID__&utm_term=__CID_NAME__&utm_content=__AID_NAME__

Dynamic tokens

TikTok calls them dynamic parameters, and the catalog is small but easy to misread. Double underscores, uppercase, at both ends__CAMPAIGN_ID__, not _CAMPAIGN_ID_ and not {campaign.id}. A single underscore on either end and TikTok can’t recognize the macro, so it lands in your URL verbatim.

The part that bites everyone is the mapping between the macro name and TikTok’s three-level hierarchy — Campaign → Ad group → Ad — plus the creative:

  • __CAMPAIGN_ID__ / __CAMPAIGN_NAME__ — the campaign. The only macro whose name matches its level.
  • __AID__ / __AID_NAME__ — the ad group, not the ad. The “A” misleads everyone. If you wanted the ad and reached for __AID__, you tagged the ad group instead.
  • __CID__ / __CID_NAME__ — the creative (the video/asset), not the campaign. Read CID as Creative ID. The campaign ID is __CAMPAIGN_ID__.
  • __ADID_V2__ / __ADID_V2_NAME__ — the actual ad ID, but only on upgraded Smart+ campaigns. On classic campaigns these resolve empty, which is why the standard template leans on the ad-group and creative levels instead.
  • __PLACEMENT__ — where the ad rendered (TikTok, TikTok Pangle). Useful as a non-standard companion when you run TikTok’s audience network.

Names break, IDs don’t. __CAMPAIGN_NAME__ returns whatever the campaign is called right now — rename it tomorrow and every UTM-based join against historical rows silently desyncs. The numeric ID variants outlive renames, restructures, and archival. Use __CAMPAIGN_ID__ for utm_id always, and consider it for utm_campaign too unless you specifically want the human-readable name in reports.

Where to put the parameters

UTM parameters are set at the ad level in TikTok Ads Manager. When you build an ad, the destination-URL section includes a UTM builder: you can let TikTok auto-add utm_source and utm_medium, or switch to Custom and paste your own template with the dynamic macros. The ad engine substitutes the macros at delivery — you’ll see the resolved values land on your site, not the raw tokens.

https://example.com/landing?utm_source=tiktok&utm_medium=cpc&utm_campaign=__CAMPAIGN_NAME__&utm_id=__CAMPAIGN_ID__&utm_term=__CID_NAME__&utm_content=__AID_NAME__

ttclid and click attribution

When someone clicks a TikTok ad, TikTok appends ttclid — the TikTok Click ID — to your landing-page URL automatically. As of April 2024 this happens without you configuring anything. The value is valid for roughly 30 days and is what the TikTok Pixel and the Events API match against to attribute a conversion back to the click.

The mechanics worth knowing:

  • Don’t add ttclid to your template. It’s auto-appended. Adding &ttclid=… by hand creates a duplicate, and the one that gets persisted may not be the one TikTok issued — which quietly degrades attribution.
  • Capture and persist it. Read ttclid on landing, store it (cookie or session) so it survives navigation, and attach it to the conversion you send back via the Pixel or Events API. Drop it and you lose attribution accuracy even with server-side tracking in place.
  • Server-side is the durable half. Safari ITP, ad blockers, and consent gates eat client-side Pixel events. Sending conversions through the Events API with the stored ttclid is how the conversion still reconciles. That click-ID-plus-UTM reconciliation is exactly the problem AnyTrack exists to handle.

For how the receiving end classifies a utm_source=tiktok&utm_medium=cpc session — and why a stray capital letter splits it — see Google Analytics .

Limitations and gotchas

  • The __AID__ / __CID__ trap. Worth repeating because it’s the one that costs people a quarter of mislabeled data: __AID__ is the ad group, __CID__ is the creative. Neither is the ad, and neither is the campaign.
  • __ADID_V2__ is Smart+ only. On classic campaigns it resolves to nothing. If you’ve standardized on it and then run a classic campaign, that field comes back empty.
  • Single-underscore typos break silently. _CAMPAIGN_ID_ is not a macro. No error — just the literal text in your URL.
  • Case sensitivity. GA4 preserves source/medium case. TikTok and tiktok are two sources. Lowercase everything, every time.
  • No keyword level. utm_term has no native TikTok meaning. Leaving it for the creative name is a convention, not a platform feature — document it so the team reads the column correctly.

Verification

  1. Preview before launch. In the ad’s URL section, TikTok shows the destination with parameters attached. Confirm every macro is double-underscored and mapped to the level you intended (especially __AID__ vs __CID__).
  2. Click your own ad. Once live, click it from the app and inspect the URL on your landing page. Confirm the macros resolved to real values and that ttclid was appended automatically.
  3. Check the source/medium in analytics. Confirm the session lands as tiktok / cpc in GA4 and rolls up under Paid Social — not Unassigned, and not split across casing variants.

Common problems

  • My UTMs arrive as literal __CAMPAIGN_ID__. Single-underscore typo, or the template was pasted somewhere TikTok doesn’t substitute. Re-copy it into the ad’s URL/parameters field and check both ends of every token.
  • My “ad” dimension is actually the ad group. You used __AID__ expecting the ad. That’s the ad group. Use __ADID_V2__ (Smart+) for the ad, or __CID__ for the creative.
  • TikTok shows in GA4 as (direct)/(none). ttclid and your UTMs were stripped between click and landing — common with link shorteners, redirect wrappers, and hash-routing apps. Test your redirect chain and confirm the parameters reach the final domain.
  • My TikTok conversions undercount vs the platform’s numbers. Client-side Pixel loss (ITP, blockers, consent). Send conversions server-side via the Events API with the stored ttclid.
  • My campaign report splits across two source rows. Casing or a stray -ads suffix. Standardize on tiktok and fix the historical rows with a GA4 filter or in your warehouse.
Token Description Substituted at
__CAMPAIGN_ID__Numeric campaign ID. Stable across renames — use it as utm_id.Click time
__CAMPAIGN_NAME__Human-readable campaign name. Changes the moment you rename the campaign.
Renaming breaks any downstream join on the name. Prefer the ID.
Click time
__AID__Ad group ID — NOT the ad ID, despite the name.
The most common TikTok footgun: AID = Ad group, not Ad.
Click time
__AID_NAME__Ad group name. Maps to utm_content in the standard template.Click time
__CID__Creative ID — the video/asset, NOT the campaign.
Second footgun: CID = Creative, not Campaign.
Click time
__CID_NAME__Creative name. Maps to utm_term in the standard template.Click time
__ADID_V2__Ad ID — only available on upgraded Smart+ campaigns.
Resolves empty on classic campaigns. Use AID/CID levels instead there.
Click time
__ADID_V2_NAME__Ad name — upgraded Smart+ campaigns only.Click time
__PLACEMENT__Where the ad rendered — e.g. TikTok, TikTok Pangle.Click time
ttclidTikTok Click ID — appended automatically to the landing URL on every ad click.
Don't add manually. Valid ~30 days; powers Pixel / Events API attribution.
Click time

Frequently asked questions

Last reviewed
Does __AID__ mean the ad ID?

No — and this is the single most common TikTok mistake. __AID__ resolves to the ad group ID, not the ad. The ad-level ID is __ADID_V2__, and it only populates on upgraded Smart+ campaigns. If you wanted the ad and used __AID__, you actually tagged the ad group.

What does __CID__ resolve to?

The creative ID — the video/asset — not the campaign. The campaign ID is __CAMPAIGN_ID__. The naming is genuinely misleading: read CID as Creative ID and __CAMPAIGN_ID__ as the campaign, and never assume CID is short for campaign.

Do I need to add ttclid to my UTM template?

No. TikTok appends ttclid to the landing-page URL automatically on every ad click (as of April 2024). Adding it by hand creates a duplicate and can break the value your Pixel or the Events API reads for attribution. Let TikTok handle the click ID; use UTMs for everything downstream needs to read.

Why are my macros showing up literally as __CAMPAIGN_ID__ in the URL?

Almost always a single-underscore typo. TikTok only recognizes a macro when it's wrapped in two underscores at each end — __CAMPAIGN_ID__, not _CAMPAIGN_ID_. A single underscore at either end means TikTok can't match it and passes the text through unchanged. Re-copy the template and check both ends of every token.

Should utm_source be 'tiktok' or 'tiktok-ads'?

Use tiktok, lowercase. GA4 treats source values as case-sensitive strings, so TikTok, tiktok, and tiktok-ads become three separate rows that split your reporting. Pick tiktok once and enforce it everywhere.

TikTok offers to add UTMs automatically — should I let it?

TikTok's auto-UTM toggle fills utm_source and utm_medium for you, but you lose control of the exact values and it can collide with a manual template. Pick one approach. If you want a consistent, GA4-aligned convention across every channel, build the template yourself (or with the builder) and leave the auto toggle off.

Why does the standard template put the creative in utm_term?

TikTok has no keyword/search-term concept — it's an interest feed, not a search engine — so utm_term has no native meaning. The convention here borrows it for the creative name (__CID_NAME__) and uses utm_content for the ad group (__AID_NAME__), mirroring how the Meta Ads template assigns term and content.

AnyTrack tools

Track this platform end-to-end

Resources from AnyTrack — the conversion tracking platform behind utm.new — for taking the UTMs you build here all the way to attribution and reporting.