Most broken attribution reports don’t come from bad tools. They come from UTM parameters that nobody agreed on. One teammate tags utm_source=Facebook, another uses facebook, a third goes fb-ads. By Q4, your “Facebook” traffic is split across nine buckets and your CMO is asking why paid social looks flat.
Here’s the short list of rules that keeps that from happening.
1. Decide on case early — and use lowercase
google and Google are different sources in GA4. They’re different in Mixpanel, Amplitude, and everywhere else. Pick lowercase and enforce it. It’s the easiest convention to remember and the one you’re least likely to break on a Monday morning.
2. Use the eight parameters for what they’re actually for
- utm_source — the platform.
google,meta,newsletter. - utm_medium — the channel type.
cpc,email,social,referral. - utm_campaign — the campaign name. Your internal one, the one you’d say out loud.
- utm_id — a unique campaign ID. GA4 uses this to tie back to Google Ads campaigns. Fill it in with your ad platform’s native macro when possible.
- utm_term — paid keyword, or ad set name for social.
- utm_content — the specific creative, link, or placement.
That leaves gclid, fbclid, and vendor click IDs — those aren’t UTMs, but they ride along in the same URL. Don’t rename them.
3. Let the platform fill in what it knows
Hard-coding a campaign ID into a URL is a mistake waiting to happen. Every ad platform worth its salt has dynamic macros: {campaignid} on Google Ads, {{campaign.id}} on Meta. Use them. The platform substitutes the real value at click time and you never have to update the URL.
That’s why our templates on utm.new pre-fill utm_id with these macros — your campaign IDs flow through to GA4 automatically.
4. Use hyphens, not spaces or underscores
utm_campaign=spring-sale-2026 is readable in a spreadsheet. utm_campaign=spring_sale_2026 is readable too, but GA4 and a handful of tools treat underscores as token separators. utm_campaign=spring%20sale%202026 is the URL-encoded version of spaces — ugly, brittle, and people will forget to encode eventually. Hyphens are the safe middle ground.
5. Keep campaign names stable for the whole campaign life
If a campaign runs from April 1 to May 15, don’t halfway through switch utm_campaign=spring-sale to utm_campaign=spring-sale-v2. Your report splits. If you really need to change something, change utm_content or utm_term — those are meant for variation.
6. Document the convention somewhere everyone looks
A README in your marketing folder. A pinned Notion page. A shared Airtable base. The worst case is the convention lives only in the head of the person who set it up — and then they go on vacation.
A minimum viable convention
If you want one to copy, start here:
utm_source = google | meta | linkedin | tiktok | newsletter | partner
utm_medium = cpc | paid-social | email | referral | social | audio
utm_campaign = lowercase-hyphen-separated-campaign-name
utm_id = {platform_macro} (auto-filled by the ad platform)
utm_content = lowercase-ad-or-creative-name
utm_term = lowercase-adset-or-keyword
That’s it. Build your first templates around this, shared across the team, and 80% of the “why is attribution broken” problems disappear.
One more thing
UTMs only tell you where the click came from. They don’t tell you whether the click converted, whether the conversion was real, or whether your ad platform is double-counting it. That’s the harder half of the problem — and one we’ll dig into in a future post.