Google AdsMetaTikTokLinkedInGA4FoundationalGuide

The UTM Naming Convention Standard for Performance Marketing Teams (2026)

One tagging standard that works across Google Ads, Meta, TikTok, LinkedIn, email, and creators, lands correctly in GA4's channel groups, survives Apple's click-id stripping, and can be enforced by an agent. Field specs, per-platform templates, and the rules that keep it clean.

Updated September 25, 202613 min read

most utm guides teach you what the five parameters mean and stop. that is not the problem. the problem is that three people on your team tag the same campaign three ways, ga4 files a third of your paid traffic under "unassigned" or "paid other," and apple strips the click id that was supposed to be your backup. this guide is the standard itself: the field specs, the per-platform templates, and the rules an agent can enforce.


what a utm standard actually is

a utm standard is not a spreadsheet of past links. it is three things:

  1. a fixed vocabulary for utm_source and utm_medium. these two fields decide which channel ga4 files a session under. they are not free text.
  2. a campaign naming convention, because on every ad platform utm_campaign should be filled by a macro from the campaign name. your campaign name is your utm. if the name is a mess, the tag is a mess.
  3. a stable join key, utm_id, carrying the platform's campaign id, so reporting survives renames and survives the day a click id gets stripped.

here is what most guides get wrong: they treat utms as something you build per link in a spreadsheet. on paid platforms you set the parameters once, at the account or campaign level, using dynamic macros, and never touch a link again. the standard is the macro template plus the naming convention that feeds it.


the fundamental shift: click ids are no longer a safe fallback

before: google ads auto-tagging appended gclid, meta appended fbclid, tiktok appended ttclid, and those click ids carried campaign, ad group, and creative context into ga4 and your warehouse. sloppy utms were survivable because the click id had the answer.

after: apple's link tracking protection, on since ios 17, removes known click identifiers such as gclid and fbclid from links opened from mail, messages, and safari private browsing. safari 26, released september 15, 2025, made advanced fingerprinting protection the default for all browsing. google introduced gbraid and wbraid as aggregate ios fallbacks, but those carry less than a gclid did.

utm parameters are plain query strings you control. when the click id is gone, the utm is the only campaign context that reaches your analytics, your crm, and your warehouse. that is why a tagging standard matters more in 2026, not less.


what this broke in existing accounts

1. ga4 channel grouping silently misfiled paid traffic

ga4 decides the channel from utm_medium first. google's documented rule for every paid channel is that the medium must match the pattern ^(.*cp.*|ppc|retargeting|paid.*)$ (google analytics help, default channel group). utm_medium=social is organic social. utm_medium=paidsocial matches (it contains "paid"). utm_medium=fb matches nothing and lands in unassigned. then, to be paid social rather than paid other, utm_source must also match google's list of social sites. utm_source=meta is not on that list. utm_source=facebook is.

2. case and separators split one campaign into five rows

google's documentation is explicit: "parameter values are case sensitive, e.g. utm_source=google is different from utm_source=Google" (google analytics help, campaign url parameters). Spring_Sale, spring_sale, spring-sale, springsale, and Spring Sale are five campaigns. every one of them was typed by someone who thought they were tagging the same thing.

3. renaming a live campaign forked its history

when utm_campaign is filled by a name macro, renaming the campaign in ads manager changes the tag from that moment on. the old rows stop, new rows start, and nobody can find the campaign's lifetime performance without a manual join. teams that never set utm_id have no key to join on.

4. google ads tags put in the wrong field

utms placed in the final url itself get baked into every ad and change per ad. utms placed in the tracking template can break landing pages when the template is malformed and trigger destination mismatch disapprovals. the final url suffix is the field built for this. accounts that grew by copy-paste have all three in use at once.

5. agencies brought their own convention to every client

three agencies, three conventions, one warehouse. utm_medium=cpc from one, paid_social from another, ppc from the third, all for the same channel. the blended dashboard shows six channels where there are two.

6. tiktok's macro names are not what they look like

in tiktok's url macros, __AID__ is the ad group id and __CID__ is the creative id (tiktok ads help, utm parameters). teams that read __AID__ as "ad id" have been reporting ad group ids as creatives since they launched.


the documented facts

there is no large public dataset on utm failure rates, so this section sticks to what the platforms document. every rule below has a source you can check.

  • ga4 files a session as paid search, paid social, paid shopping, paid video, or paid other only when utm_medium matches ^(.*cp.*|ppc|retargeting|paid.*)$. the source list then decides which paid channel. google ads campaigns that are auto-tagged and linked are classified from google ads metadata, not utms, which is how performance max lands in cross-network regardless of what you tag. (google analytics help, default channel group.)
  • ga4 parameter values are case sensitive. utm_id and utm_source_platform are recommended alongside the three required parameters. utm_creative_format and utm_marketing_tactic exist in the spec but google notes they are not currently reported in ga4 properties. (google analytics help, campaign url parameters.)
  • google ads exposes campaign and ad group ids, creative id, keyword, match type, network, device, placement, and location through valuetrack. it does not expose campaign names. {keyword} returns blank in ai max for search, dynamic search ads, and performance max. {matchtype} returns a for ai max keywordless and {network} returns x for performance max. (google ads help, valuetrack parameters)
  • meta exposes {{campaign.id}}, {{campaign.name}}, {{adset.id}}, {{adset.name}}, {{ad.id}}, {{ad.name}}, {{placement}}, and {{site_source_name}} in the url parameters field. {{site_source_name}} resolves to short codes such as fb, ig, msg, and an, not to names ga4 recognizes as social sources. (meta business help center, url dynamic parameters.)
  • tiktok exposes __CAMPAIGN_NAME__, __CAMPAIGN_ID__, __AID_NAME__, __AID__ (ad group), __CID_NAME__, __CID__ (creative), __PLACEMENT__, and for upgraded smart+ campaigns __ADID_V2_NAME__ and __ADID_V2__. (tiktok ads help, utm parameters.)
  • linkedin's dynamic tracking parameters resolve ACCOUNT_ID, ACCOUNT_NAME, CAMPAIGN_GROUP_ID, CAMPAIGN_GROUP_NAME, CAMPAIGN_ID, CAMPAIGN_NAME, CREATIVE_ID, and from api version 202606 CREATIVE_NAME. they can be set at the campaign level, and from version 202608 at the ad account level, and they apply to every creative under that scope without re-review. conversation ads and message ads are not supported. (linkedin marketing api docs, dynamic utm tracking)

what changed in 2026 specifically

september 2025 onward: safari 26 and ios 26 shipped with advanced fingerprinting protection on by default and link tracking protection covering links from mail, messages, and private browsing. click ids on apple traffic are unreliable. treat utm_id as the primary campaign key and click ids as a bonus.

linkedin, 2026: creative names became available as a dynamic parameter (api version 202606) and tracking parameters moved up to the ad account level (202608). a linkedin account can now carry one template for every campaign, the way google ads has with account-level final url suffix.

tiktok, 2026: smart+ campaigns expose a real ad id (__ADID_V2__) and ad name. legacy campaigns still only expose ad group and creative. one template no longer fits every tiktok campaign type.

google ads, ongoing: ai max for search returns blank keywords and a new a match type. any reporting that keys on utm_term={keyword} is showing blanks for a growing share of search spend. key on {targetid} and {adgroupid} instead.

ga4, unchanged: the channel rules above have not moved. the mistakes have not moved either.


the standard

field spec

parameterruleallowed values or format
utm_sourcethe platform, as ga4 names itgoogle, facebook, instagram, tiktok, linkedin, pinterest, snapchat, youtube, bing, klaviyo, hubspot, a creator handle, a partner domain
utm_mediumthe channel, from a closed listcpc (search and shopping), paid-social, paid-video, display, email, sms, affiliate, organic-social, referral
utm_campaignmacro from the campaign namesee the naming convention below
utm_contentmacro from the ad or creative name{format}-{hook}-{v#}
utm_termsearch: target id. social: ad set or ad group namemacro
utm_idplatform campaign id, alwaysmacro

rules that apply to every field:

  • lowercase only. the platform macros pass names through as typed, so the naming convention below is lowercase too.
  • hyphens inside a field, underscores between fields. never spaces, never mixed.
  • ascii only. no accents, no emoji, no currency symbols.
  • no personal data, ever. no emails, no names, no customer ids in any query string.
  • never put a utm on a link from your own site to your own site. it resets the session source and overwrites the real one.

campaign naming convention

campaign names feed utm_campaign on every platform, so the name is the tag. fields, in order, separated by underscores:

{objective}_{funnel}_{audience}_{geo}_{yymm}

  • objective: conv, lead, traffic, aware, app, sales
  • funnel: pros (prospecting), rmkt (remarketing), ret (retention)
  • audience: broad, lal, int-{topic}, list-{name}, asc, pmax
  • geo: iso country or region: us, uk, eu, latam, row
  • yymm: launch month: 2609

example: conv_pros_broad_us_2609. that string is the campaign name in ads manager and, through the macro, the utm_campaign value. anyone reading a ga4 row knows the objective, funnel stage, audience, geography, and launch month without a lookup.

ad set and ad group names carry the audience detail: {audience}_{placement-or-geo}_{yymm}. ad names carry creative identity: {format}-{hook}-{v#}, for example video-problem-v3 or static-testimonial-v1.

per-platform templates

google ads, account-level final url suffix. keep auto-tagging on. google does not expose campaign names in valuetrack, so campaign identity comes from the id and is joined to the name in reporting.

utm_source=google&utm_medium=cpc&utm_campaign={campaignid}&utm_content={creative}&utm_term={targetid}&utm_id={campaignid}&net={network}&dev={device}&mt={matchtype}

put it in the final url suffix, never in the final url and never in the tracking template. use a campaign-level suffix only to override the medium for video (paid-video) or display (display).

meta, url parameters field at the ad level. use facebook or instagram as the source so ga4 files it as paid social. put placement breakdown in a custom parameter, not in the source.

utm_source=facebook&utm_medium=paid-social&utm_campaign={{campaign.name}}&utm_content={{ad.name}}&utm_term={{adset.name}}&utm_id={{campaign.id}}&placement={{placement}}&site={{site_source_name}}

tiktok, url builder or manual parameters. remember __AID__ is the ad group and __CID__ is the creative.

utm_source=tiktok&utm_medium=paid-social&utm_campaign=__CAMPAIGN_NAME__&utm_content=__CID_NAME__&utm_term=__AID_NAME__&utm_id=__CAMPAIGN_ID__&placement=__PLACEMENT__

for upgraded smart+ campaigns, swap utm_content=__CID_NAME__ for utm_content=__ADID_V2_NAME__.

linkedin, dynamic tracking parameters at the ad account level (api version 202608 or later). static values go in custom parameters, dynamic values map to the enums.

custom: utm_source=linkedin, utm_medium=paid-social
dynamic: utm_campaign=CAMPAIGN_NAME, utm_content=CREATIVE_NAME, utm_id=CAMPAIGN_ID, cg=CAMPAIGN_GROUP_NAME

linkedin appends li_fat_id on its own. leave it alone.

email and sms. utm_source={esp} (klaviyo, hubspot, braze), utm_medium=email or sms, utm_campaign={flow-or-send}_{yymm}, utm_content={variant}. ga4's email rule matches on either source or medium, so utm_medium=email is the one that must be exact.

creators and affiliates. for whitelisted or paid creator posts on a social platform: utm_source=instagram&utm_medium=paid-social&utm_campaign=creator-{handle}_{yymm}. for organic creator links: utm_medium=organic-social. for affiliate networks: utm_medium=affiliate, utm_source={network}. if you want creators as their own channel in ga4, build a custom channel group keyed on the creator- prefix. do not invent utm_medium=influencer; ga4 has no rule for it and it lands in unassigned.

governance

  • one owner. the standard lives in one document, and one person approves changes to the allowed value lists.
  • the value lists are the test. anything not on the list is a defect, not a creative choice.
  • a weekly check of distinct utm_source and utm_medium values in ga4. new values that were not approved are the drift.
  • never rename a live campaign. if you must, note the old and new name against the utm_id so the join survives.

what to stop doing immediately

  • stop building paid links in a spreadsheet. set the template once per platform and let the macros fill it.
  • stop using utm_source=meta. ga4 does not treat it as a social source.
  • stop using utm_medium=social for paid traffic. it is filed as organic.
  • stop using {keyword} as your search key. it returns blank for ai max, dynamic search ads, and performance max.
  • stop putting utms in the google ads final url or tracking template. final url suffix only.
  • stop tagging internal links.
  • stop renaming live campaigns without recording the utm_id mapping.
  • stop treating gclid and fbclid as the source of truth on apple traffic.

the orbit agent instructions

{
  "guide": "utm-naming-convention-standard",
  "agent_tasks": {
    "audit_utm_presence_per_ad": {
      "check": "pull the effective landing url or url parameters for every active ad across google ads (final url suffix), meta (url parameters), tiktok (url parameters), and linkedin (tracking parameters)",
      "flag": "any active ad whose effective url is missing utm_source, utm_medium, utm_campaign, or utm_id",
      "recommend": "set the platform's account-level or campaign-level template from this guide so every ad inherits the parameters"
    },
    "audit_utm_vocabulary": {
      "check": "list distinct utm_source and utm_medium values from ga4 session_source and session_medium over the last 30 days and from ad platform url parameters",
      "flag": "any value not on the allowed lists, any uppercase character, any space or encoded space, utm_source=meta, utm_medium=social on paid ads, utm_medium=influencer",
      "recommend": "map each offending value to its allowed replacement and update the template that produces it"
    },
    "audit_ga4_channel_mapping": {
      "check": "for the last 30 days, compute the share of paid sessions ga4 files under unassigned or paid other versus paid search, paid social, paid video, paid shopping, cross-network",
      "flag": "unassigned or paid other above 5 percent of paid sessions, or any known paid source appearing under organic social",
      "recommend": "fix utm_source and utm_medium at the template so sessions match google's channel rules, and add a custom channel group only for channels ga4 has no rule for, such as creators"
    },
    "audit_campaign_name_compliance": {
      "check": "parse every active campaign name against the pattern objective_funnel_audience_geo_yymm with lowercase, underscores between fields, hyphens within fields",
      "flag": "any campaign name that does not match, contains uppercase or spaces, or has fewer than five fields",
      "recommend": "propose the compliant name and record the campaign id so history can be joined after the rename"
    },
    "audit_click_id_fallback": {
      "check": "confirm google ads auto-tagging is enabled, ga4 and google ads are linked, and utm_id is present in every platform template",
      "flag": "auto-tagging off, no ga4 link, or any template without utm_id",
      "recommend": "enable auto-tagging, link the accounts, and add utm_id so campaign context survives apple's click-id stripping"
    },
    "monitor_utm_drift_weekly": {
      "check": "each week, compare the set of distinct utm_source, utm_medium, and utm_campaign values against last week",
      "flag": "any new utm_source or utm_medium value, or a utm_campaign that changed value while the same utm_id kept running",
      "recommend": "report the new values, identify which platform template or campaign rename produced them, and correct the template rather than the reports"
    }
  }
}

the bottom line

your campaign name is your utm. set the macro template once per platform, name campaigns to the convention, keep utm_source and utm_medium inside ga4's rules, and carry the platform campaign id in utm_id so nothing depends on a click id apple may strip.

the standard is short. the discipline is the hard part, and that is exactly the part an agent can check every week.


built by orbit - the performance marketing intelligence layer. questions? jose@orbitllm.com