| utm_source | tiktok |
| utm_medium | cpc |
| 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.
The recommended UTM template
| Parameter | Value | Why |
|---|---|---|
utm_source | tiktok | Lowercase, no -ads suffix. GA4 splits TikTok / tiktok / tiktok-ads into separate rows. |
utm_medium | cpc | Matches 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. ReadCIDas 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
ttclidto 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
ttclidon 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
ttclidis 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.
TikTokandtiktokare two sources. Lowercase everything, every time. - No keyword level.
utm_termhas 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
- 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__). - 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
ttclidwas appended automatically. - Check the source/medium in analytics. Confirm the session lands as
tiktok/cpcin 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).ttclidand 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
-adssuffix. Standardize ontiktokand 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 |
| ttclid | TikTok 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 |

