Most broken analytics I have seen were not broken by a bug. They were broken by three people tagging links slightly differently for six months.
UTM parameters have no schema. Nothing validates them. Your analytics tool takes whatever string you put in utm_source and treats it as gospel, which means the discipline has to live in you, not the tool. Here is a convention that takes ten minutes to adopt and saves you from a report you cannot trust.
The five parameters, and what each is actually for
-
utm_source: where the click came from. A single named place:newsletter,instagram,partner-acme. -
utm_medium: what kind of channel it is:email,social,cpc,qr,referral. -
utm_campaign: which initiative it belongs to:spring-launch,black-friday-2026. -
utm_content: which specific link, when one page has several:header-cta,footer-link. -
utm_term: paid keyword. Mostly vestigial unless you are running search ads.
The distinction people get wrong is source versus medium. Source is the place, medium is the type. Instagram is a source; social is a medium. Your newsletter is a source; email is a medium. If you find yourself putting instagram in medium, the whole report will fragment later.
Rule 1: lowercase everything, always
This is the single highest-value rule, so it goes first.
utm_source=Instagram
utm_source=instagram
utm_source=INSTAGRAM
Most analytics tools treat those as three different sources. You will not notice for a month. Then you will open a report, see Instagram split across three rows, and have no clean way to merge history.
Lowercase everything. No exceptions, no judgment calls.
Rule 2: hyphens, never spaces or underscores
A space becomes %20 and looks broken in reports. Underscores are fine technically but mixing them with hyphens gives you the same fragmentation problem as casing.
❌ utm_campaign=Spring Launch
❌ utm_campaign=spring_launch
✅ utm_campaign=spring-launch
Pick hyphens. Write it down. Done.
Rule 3: date your campaigns
utm_campaign=black-friday seems fine until it is your third Black Friday and every year is stacked into one row.
✅ utm_campaign=black-friday-2026
✅ utm_campaign=2026-03-product-launch
Year-first works well if you want campaigns to sort chronologically.
Rule 4: never tag internal links
This is the one that silently corrupts data.
If you tag a link from your own homepage to your own pricing page, most analytics tools start a new session at that click and overwrite the original referrer. The visitor came from a newsletter, clicked one internal link, and is now attributed to your own site.
UTMs are for traffic arriving from outside. Internal navigation is what your normal page-path reporting is for.
Rule 5: keep a canonical list
Not a spreadsheet nobody opens. A short list in whatever doc your team actually reads:
sources: newsletter, instagram, tiktok, linkedin, youtube, partner-<name>
mediums: email, social, cpc, qr, referral, print
campaign: <yyyy>-<mm>-<short-name>
content: header-cta, inline-link, footer-link, bio-link
The rule is: if it is not on the list, it does not get used until it is added to the list. That single sentence is what prevents drift, because the failure mode is never one bad decision, it is fifty small ones.
Rule 6: think about what the user sees
A URL like this in an Instagram bio is ugly, and it leaks your internal campaign naming to anyone who looks:
https://example.com/pricing?utm_source=instagram&utm_medium=social&utm_campaign=2026-03-launch&utm_content=bio-link
This is where a short link earns its place. The tagged URL becomes the destination, and the thing you publish stays clean. You keep the attribution and the reader gets a link that fits.
It also means the tagging lives in one editable place. Get a UTM wrong on a printed QR code and you are reprinting; get it wrong behind a short link and you fix the destination.
Rule 7: QR codes need utm_medium=qr
Scans from print are not "direct" traffic, but that is where they land if you do not tag them. Tag the URL behind the code, and if the same campaign runs on a poster and a flyer, separate them with utm_content:
utm_source=poster&utm_medium=qr&utm_campaign=2026-03-launch&utm_content=cafe-window
Now "did the flyers do anything" is a question with an answer.
A worked example
Spring launch, promoted through the newsletter, Instagram bio, and a printed flyer:
# newsletter, main button
?utm_source=newsletter&utm_medium=email&utm_campaign=2026-03-spring-launch&utm_content=header-cta
# instagram bio link
?utm_source=instagram&utm_medium=social&utm_campaign=2026-03-spring-launch&utm_content=bio-link
# flyer QR code
?utm_source=flyer&utm_medium=qr&utm_campaign=2026-03-spring-launch&utm_content=cafe-window
Same campaign across all three, so they roll up. Different sources and mediums, so they break down. That is the whole point.
The check that catches drift
Once a month, list your distinct utm_source values. If you see instagram and Instagram, or ig and insta, drift has started. Fix the convention now, because merging historical rows is unpleasant and sometimes impossible.
I build Swyfty, a short-link and analytics tool, which is why I have opinions about this. But none of the above needs my product or any product. It needs a list of allowed values and the discipline to stick to it.
The tooling is never what makes attribution work. Consistency is. A boring convention applied every time beats a sophisticated analytics stack fed inconsistent strings, every single time.
Top comments (0)