Most UTM problems are not tracking problems. They are naming problems. The tag fires correctly, GA4 records it, and three months later nobody can tell whether FB, facebook, Facebook_Ads and fb-paid were four campaigns or one. This guide gives you a naming convention that survives contact with a real team, plus a template you can copy into a spreadsheet today.
If you are new to UTM parameters, start with our UTM tracking guide and come back. This article assumes you know what the five parameters do and want them to stay clean.
Why UTM naming breaks in every team
UTM tags are free text. Google does not validate them, does not normalize case, and does not merge near-duplicates. That means every person who builds a link is quietly defining your reporting taxonomy. Four things go wrong almost every time:
- Case drift.
utm_source=LinkedInandutm_source=linkedinare two separate sources in every GA4 report. - Parameter confusion. One person puts the platform in
utm_medium, another puts the ad format there, a third leaves it blank. - Campaign names that mean something only to the author.
utm_campaign=q3push2made sense in July. Nobody remembers by October. - Special characters. Spaces become
%20, ampersands break the URL, and accented characters render as noise in reports.
The fix is not more discipline. It is a convention simple enough that people follow it without thinking, plus one shared place where links get built.
The five rules
Rule 1: Lowercase everything, always
No exceptions, no proper nouns. linkedin, not LinkedIn. This single rule removes more duplicate rows from your reports than any other. GA4 does not offer retroactive case normalization, so the fix has to happen at the link.
Rule 2: Separate words with underscores, never spaces or hyphens
Pick one separator and use it inside every value. Underscores are the safest choice: they survive URL encoding, are readable in a spreadsheet, and do not collide with hyphens that already appear in product names and dates. spring_sale, not spring-sale and never spring sale.
Rule 3: utm_source is the platform, utm_medium is the channel type
This is where most teams argue, so lock it down explicitly. Source answers “where did the click physically come from.” Medium answers “what kind of marketing was it.” A short list of allowed mediums keeps GA4 default channel grouping working:
| utm_medium | Use for | GA4 channel it maps to |
|---|---|---|
| cpc | Paid search, paid social with cost per click billing | Paid Search or Paid Social |
| paid_social | Meta, LinkedIn, TikTok ads | Paid Social |
| display | Banner and programmatic | Display |
| Newsletters, nurture sequences, one-off sends | ||
| social | Organic posts on any network | Organic Social |
| referral | Partner links, guest posts, directories | Referral |
| affiliate | Affiliate and influencer links | Affiliates |
| video | YouTube, Vimeo, embedded video | Paid Video or Organic Video |
Note that GA4 channel grouping is strict about medium. If you invent utm_medium=facebook, the traffic lands in Unassigned and disappears from your acquisition reports. Our comparison of GA4 vs Universal Analytics UTM handling covers this in more detail.
Rule 4: utm_campaign follows a fixed pattern
The campaign value is where free-text chaos lives. Replace it with a pattern that encodes the three things you actually filter by later: the goal, the offer, and the date. A format that works for teams from two people to two hundred:
{objective}_{offer}_{yyyymm}
Examples:
leadgen_pricing_calculator_202609retention_annual_upgrade_202610awareness_geo_report_202609
Keep the objective list short. Five values cover most businesses: awareness, leadgen, sales, retention, event. The date goes last so that campaign names sort chronologically in any report, and it uses year first so that sorting works across year boundaries.
Rule 5: utm_content and utm_term are for variants, not descriptions
utm_content distinguishes creatives or placements inside one campaign: video_a, video_b, carousel_testimonials, header_link, footer_link. utm_term is reserved for paid search keywords and, if you like, audience names in paid social: lookalike_customers_1pct. If a value does not help you compare two things, it does not belong in these fields.
The template
Put this in a shared Google Sheet with one row per link. Columns A through E are inputs, column F builds the URL with a formula, and G through I are for ownership. Freeze the header, lock the formula column, and turn on data validation dropdowns for source and medium so people cannot type a new value without asking.
| Column | Field | Validation | Example |
|---|---|---|---|
| A | Landing URL | Must start with https:// | https://rivatra.com/cpl-vs-cpql/ |
| B | utm_source | Dropdown: google, linkedin, meta, newsletter, partner, youtube | |
| C | utm_medium | Dropdown: cpc, paid_social, email, social, referral, display, video | paid_social |
| D | utm_campaign | Pattern check, lowercase, underscores | leadgen_cpl_guide_202609 |
| E | utm_content | Optional, lowercase | carousel_v2 |
| F | Final URL | Formula, locked | built automatically |
| G | Owner | Name | Maria |
| H | Created | Date | 2026-09-12 |
| I | Notes | Free text | Q3 LinkedIn test, budget $1.5k |
The formula for column F in Google Sheets:
=A2&IF(ISNUMBER(FIND("?",A2)),"&","?")&"utm_source="&LOWER(B2)&"&utm_medium="&LOWER(C2)&"&utm_campaign="&LOWER(SUBSTITUTE(D2," ","_"))&IF(E2="","","&utm_content="&LOWER(SUBSTITUTE(E2," ","_")))
It handles landing pages that already have a query string, forces lowercase, and swaps stray spaces for underscores. It will not stop someone from typing a hyphen, so keep the dropdowns on the two fields that matter most.
For Google Ads specifically you should not build links by hand at all. Use a tracking template at the account level so every ad inherits the same structure. We walk through the setup in how to add UTM parameters to Google Ads.
A worked example across four channels
Say you are promoting a new pricing calculator in September 2026. One offer, four channels, one campaign name:
| Channel | utm_source | utm_medium | utm_campaign | utm_content |
|---|---|---|---|---|
| LinkedIn sponsored post | paid_social | leadgen_pricing_calculator_202609 | single_image_stat | |
| LinkedIn sponsored post, variant | paid_social | leadgen_pricing_calculator_202609 | video_demo_15s | |
| Weekly newsletter | newsletter | leadgen_pricing_calculator_202609 | hero_button | |
| Partner blog mention | partner_acme | referral | leadgen_pricing_calculator_202609 | inline_link |
| Google Search | cpc | leadgen_pricing_calculator_202609 | set by tracking template |
In GA4 you now filter on one campaign value and see all five rows side by side. Compare sources for volume, compare content for creative performance, and total cost per qualified lead per channel without touching a single regex. If you want to see how that comparison plays out, our article on CPL vs CPQL uses exactly this structure.
Rolling it out without a fight
- Write the rules on one page. The five rules above fit on a single screen. Pin it in your team wiki and link it from the header of the sheet.
- Freeze the dropdowns. Adding a new source or medium should require a two-line message to whoever owns analytics. That friction is the point.
- Audit once a month. In GA4, open Reports, Acquisition, Traffic acquisition, switch the primary dimension to Session source / medium, and scan for anything with uppercase letters, spaces, or a medium not on your list. Ten minutes catches most drift.
- Do not retro-tag old links. Links already in the wild keep whatever they had. Start clean from a date, note that date in the sheet, and accept a messy history.
- Add a channel grouping rule for legacy mediums. If old links used
utm_medium=facebook, create a custom channel group in GA4 that maps it to Paid Social so historical reports still make sense.
Quick reference
- Lowercase only.
- Underscores between words.
- Source is the platform, medium is from the approved list.
- Campaign is
objective_offer_yyyymm. - Content and term exist to compare variants.
- One sheet, dropdowns on, formula locked.
None of this is clever. That is why it works. A naming convention succeeds when the person building a link at 6pm on a Friday cannot get it wrong, and a dropdown beats a policy document every time.