A UTM naming convention is the set of rules that decides how your team writes campaign tags, so that the same channel always produces the same string. It matters because UTM values are case-sensitive and free-form, which means nothing stops three people from tagging the same channel as facebook, Facebook, and FB. Your analytics tool then treats those as three separate sources, and your Facebook number is wrong in three places at once.
That is the whole problem in one sentence: inconsistent tags fragment reports. The fix is not more discipline. The fix is a written convention plus a tool that enforces it. The core rule set is short. Lowercase everything. No spaces, one delimiter. Define a controlled vocabulary for utm_source and utm_medium so people pick from a list instead of inventing values. Keep personal data out of the URL. Document it once and lock it where links get made. The rest of this post fills in each rule, gives you a taxonomy table you can copy, and covers how to enforce the convention so it survives contact with a busy launch week.
This is the governance companion to the end-to-end UTM tracking walkthrough and the UTM builder feature post. Those cover the pipeline and the tooling. This one is about the naming rules themselves.
Why a UTM naming convention matters#
Open any GA4 property that has run campaigns for a year without governance, and you will find the same wreckage. The source dimension has facebook, Facebook, FB, fb, facebook.com, and meta, all of which are the same channel. The medium has email, Email, e-mail, and newsletter competing for the same idea. Each variant is its own row. Each row holds a slice of the traffic. Adding them back together is a manual, error-prone afternoon every time someone asks "how did Facebook do".
The cost is not only tidiness. Paid platforms read your conversion data back to optimize spend. If half your paid social clicks land under utm_medium=social and the other half under paid-social, GA4's default channel grouping files some as organic, your paid reporting underreports, and the finance question "why doesn't paid spend show up in attributed revenue" has no clean answer. We dig into which of those numbers to trust in short link analytics: what to actually measure.
UTM parameters are old. The convention came out of Urchin, the web analytics product Google acquired in 2005 and built into what became Google Analytics. The acronym still stands for Urchin Tracking Module. The original __utm.js script had no template layer and no validation; the rule was always "type it consistently", and the tooling never enforced it. Two decades later, most teams are still relying on memory. That is the gap a convention closes.
The five UTM parameters and what each should hold#
There are five parameters. Three are effectively required for clean reporting; two are optional and routinely misused. Getting the division of labor right is most of the battle, because most drift starts as confusion about which value belongs where.
utm_source names where the click came from: the specific platform, publication, or partner. google, newsletter, partner-acme. It answers "which property sent this".
utm_medium names how it got there: the marketing category. cpc, email, social, referral, affiliate. It answers "what kind of channel is this". Source is the proper noun, medium is the category it belongs to.
utm_campaign names the initiative the link is part of. spring-sale-2026, q3-product-launch. This is the value you slice reports by, so its format matters most for downstream regex.
utm_content distinguishes variants within one campaign and source: the creative, the placement, the A/B arm. hero-banner, carousel-v2, footer-link. Use it when you have more than one link pointing at the same destination from the same campaign and need to tell them apart.
utm_term was built for paid-search keywords and is best kept to that. If you are not running paid search, leave it null rather than turning it into a junk drawer for metadata that did not fit elsewhere.
The single most common structural error is swapping source and medium. utm_source=cpc is wrong because cpc is a category, not a place. utm_medium=google is wrong because google is a place, not a category. The correct pairing is utm_source=google, utm_medium=cpc. Decide the rule once, write it next to each parameter in your doc, and the swap stops happening.
UTM parameter standards: case, spaces, and delimiters#
Three formatting rules eliminate most drift, and all three are cheap to apply once and expensive to skip.
Lowercase everything. GA4 treats Email and email as different values, so capitalization drift silently multiplies your channels. There is no reason to allow uppercase in a UTM value; pick lowercase and never deviate.
No spaces, ever. A space in a URL encodes to %20, so utm_campaign=spring sale arrives in your reports as spring%20sale, which breaks the campaign-name regex teams use to group funnels and looks broken in every dashboard. Replace spaces at the source.
One delimiter, used everywhere. Pick a hyphen or an underscore for separating words inside a value and commit to it. Mixing them gives you spring-sale and spring_sale as separate campaigns, which is the same fragmentation problem wearing a different hat. Hyphens are the common choice because they match URL-slug habits and read cleanly: q3-launch-dach. Whichever you choose, the rule is consistency, not the specific character.
These standards line up with Google's own UTM guidance, which tells teams to be consistent and use lowercase. The advice is correct. What Google's Campaign URL Builder does not do is enforce any of it, which is why a convention on paper drifts the moment a deadline hits.
Controlled vocabularies for source, medium, and campaign#
A naming convention that says "use lowercase and hyphens" still lets someone invent utm_source=the-newsletter when the agreed value is newsletter. The fix is a controlled vocabulary: a fixed list of allowed values for the parameters where the set is knowable in advance.
utm_medium should be a closed enum. The marketing categories you use are countable and stable. A sane default list:
cpcfor paid searchpaid-socialfor paid placements on social platformssocialfor organic socialemailfor newsletters and lifecycle mailreferralfor partner and word-of-mouth linksaffiliatefor affiliate-network trafficdisplayfor banner and programmaticqrfor codes on print and packaging
If a value is not on the list, it should be rejected, not silently accepted. That single rule kills the social versus paid-social confusion that wrecks channel grouping.
utm_source is semi-controlled. For platforms it should be an enum (instagram, linkedin, tiktok, youtube, facebook, x), because that is where capitalization and abbreviation drift live worst. For partners and publications, bind it to a real list, your CRM partner accounts or your media plan, so an off-list source forces an explicit decision instead of a guess.
utm_campaign cannot be a closed enum because campaigns are created constantly, but it should still follow a pattern. A useful shape is quarter-theme-region: q3-launch-dach, q4-blackfriday-eu. The pattern makes campaigns sortable and lets a regex group a whole quarter or region in one expression.
A real UTM taxonomy table#
Here is a taxonomy you can adapt today. It maps each common channel to the exact values your team should produce, which is what turns a convention from prose into something a person can follow under deadline.
| Channel | utm_source | utm_medium | utm_campaign pattern | utm_content | utm_term |
|---|---|---|---|---|---|
| Newsletter | newsletter | email | quarter-theme | creative-variant | null |
| Lifecycle email | lifecycle | email | flow-name | step-id | null |
| Organic Instagram | instagram | social | quarter-theme | post-id | null |
| Paid Meta | facebook | paid-social | campaign-id | ad-id | null |
| Google Search ads | google | cpc | campaign-id | ad-id | {keyword} |
| Partner referral | partner-{name} | referral | deal-id | placement | null |
| Affiliate | affiliate-{net} | affiliate | program-name | sub-id | null |
| QR on print | print | qr | quarter-collateral | placement | null |
The pattern columns are deliberate. utm_content carries the variant identifier so you can compare creatives within a campaign; for paid channels, use the platform's native ad ID rather than a human label, because the label belongs in the ad manager and the stable ID belongs in the URL. Keep utm_term null unless you are running paid search, where it holds the matched keyword.
Common UTM mistakes that fragment reports#
The failure modes repeat across every team I have audited. Naming the ones below and writing the fix next to each is most of what a convention document is for.
Capitalization drift is the big one. Facebook, facebook, and FB become three sources because the values are case-sensitive and unconstrained. The fix is a lowercase transform applied at assembly time and an enum that does not contain FB.
Putting the medium in the source, or the source in the medium. utm_source=cpc and utm_medium=google both invert the model. The fix is the controlled vocabulary plus the source-is-where, medium-is-how rule written where people can see it.
Spaces and mixed delimiters in utm_campaign. Spring 2026 DACH becomes Spring%202026%20DACH, and spring-sale versus spring_sale splits one campaign in two. The fix is a slug transform that lowercases, replaces spaces, and normalizes the delimiter before the value is ever committed.
Personal data in the query string. This one is a compliance problem, not a tidiness one. A UTM value lives in the URL, which is logged by web servers, sits in browser history, gets forwarded in referrer headers, and is frequently pasted into chat in plain text. An email address, a name, or any other identifier in a utm_ field is personal data sitting in an unprotected place. The European Data Protection Board's guidance on transparency and data minimization points the same direction: do not collect or expose personal data you do not need, and a URL is about the worst place to keep any. Keep UTMs to campaign metadata. If you need to tie a click to a person, do it server-side against an ID, not in a query parameter. The consent side of this lives in Consent Mode v2 for tracking.
utm_term as a dumping ground. Without a rule, it collects whatever did not fit elsewhere. Define what it is for (paid-search keyword, null otherwise) and the temptation goes away.
Enforcing consistent UTM tags with templates#
A convention that lives only in a document drifts. People forget, new hires never read it, and a Friday deadline beats good intentions. Enforcement has to move into the tool that assembles the links, so the rules apply whether or not anyone remembers them.
The pattern that holds is a workspace template with the controlled vocabularies baked in. You write the convention once at the workspace level, define utm_medium as a literal where it never varies (email for the newsletter template), bind utm_source to an enum, and let placeholders fill the rest from the link payload. A new marketer cannot then produce a malformed utm_source, because the template rejects anything off the list. The lowercase and slug transforms apply automatically, so consistency stops depending on per-person discipline.
A shortener that owns the assembly step can do three things a standalone form cannot: hold the template, validate every input against it, and refuse to commit a link that violates the rules. When Elido assembles the link, the resolved value and the final value are both recorded, so a per-link override leaves an audit trail with who changed it and when. The full template syntax, including per-channel templates and placeholder paths, is in the UTM templates guide, and the broader case for marketers is on the marketers solutions page. For the analytics that depend on this hygiene, see Elido analytics.
The honest scope: templates fix tagging hygiene and audit. They do not fix cross-device attribution or the server-side forwarding that survives Safari ITP, both of which are separate problems covered in the end-to-end walkthrough. What they do fix is the thing that quietly breaks every report: the same channel arriving under five different names.
A copy-paste convention and spreadsheet template#
If you are not ready to move assembly into a tool yet, start with a written convention and a tracking sheet. Both are better than memory, and they are the artifact you hand a tool later.
The convention block, short enough to paste into a team wiki:
UTM CONVENTION (v1)
- All values lowercase. No exceptions.
- Words separated by hyphens. No spaces, no underscores, no other delimiters.
- utm_source: where the click came from. Enum for platforms; CRM list for partners.
- utm_medium: how it got here. Closed enum only:
cpc | paid-social | social | email | referral | affiliate | display | qr
- utm_campaign: quarter-theme-region. e.g. q3-launch-dach
- utm_content: variant id (creative, placement, ad-id). Optional.
- utm_term: paid-search keyword only. null otherwise.
- Never put names, emails, or any personal data in a UTM. Ever.
The spreadsheet template needs one tab for the controlled vocabularies and one for the links. Structure it like this:
- A
vocabtab with one column per controlled parameter (source,medium), each holding the approved values. This is the single source of truth that data validation rules point at. - A
linkstab with columns for the destination URL, each UTM value (validated against thevocabtab so a typo is rejected on entry), an assembled-URL column that concatenates them, and a free-text notes column for context. - A data-validation rule on the medium and source columns so the cells only accept values from the
vocabtab. That is the closest a spreadsheet gets to enforcement.
When the sheet outgrows manual entry, the column names map directly onto template placeholders, and the same CSV imports straight into a bulk-create endpoint. The convention you wrote on day one becomes the schema the tool enforces on day one hundred. Pricing for the tiers that include workspace templates is on the pricing page.
A naming convention is boring infrastructure, which is exactly why it gets skipped and exactly why skipping it costs a quarter of clean data. Write the rules down, lock them where links are made, and your reports start adding up again.
Related on the blog#
- Track UTM campaigns end-to-end without a CDP - the full pipeline this convention feeds.
- Link shortener with a UTM builder - the tooling that enforces the rules.
- Short link analytics: what to actually measure - reading the reports once the tags are clean.
- What is a URL shortener - the foundation if you are starting from scratch.