UTM naming linter
UTM values are case-sensitive, so Newsletter and newsletter become two rows in every report, and there is no retroactive fix. Paste the links your team has actually been sending and this finds the drift — including the case where the same logical value is spelled three ways across a campaign, which is invisible until you group them.
Issues
Values seen (variants of the same value grouped together)
Summary
How to use
- Paste the campaign URLs. Get them from wherever the links actually live — the email tool, the ad platform export, a
utm_sourcereport in GA — rather than from the brief, because the brief is not what shipped. - Read the Issues table. Each row names the line, the parameter, the problem, and why it matters in reporting terms.
- Check Values seen. Rows are grouped by lowercase value, so a value spelled several ways appears once with all its variants listed and is outlined — that is your case-drift report.
- Copy report gives you a plain-text version to send to whoever is building the links.
What it checks and why each one matters
Case drift in values. The core problem. GA4 does not normalise case, so every capitalisation variant is a separate dimension value. A campaign split across Summer-Launch, summer-launch and Summer-launch reports as three campaigns with a third of the traffic each.
Spaces. A space arrives as %20 or + depending on who built the link, and those are two different values. Hyphens avoid the question entirely.
Missing source or medium. GA4 needs both to attribute a session to a campaign. A link with utm_campaign and utm_source but no utm_medium lands in Unassigned — the traffic arrives, the campaign gets no credit.
utm_medium outside the recognised vocabulary. GA4 derives its default channel groupings from specific medium values: email, cpc, organic_social, paid_social, referral, affiliate, display and a handful more. Writing newsletter or facebook-ad in utm_medium is the most common UTM error there is, and it sends the traffic to Unassigned. The channel name goes in utm_medium; the specific property goes in utm_source.
Duplicated parameters. ?utm_source=a&utm_source=b resolves differently in different tools — first value, last value, or both concatenated. Usually caused by appending UTMs to a URL that already had them.
Personal data in parameters. An email address in utm_content or utm_term is a real problem: URLs end up in analytics exports, server logs, referrer headers sent to third parties, and browser history. Under GDPR that is personal data processed in places you did not intend, and GA's own terms prohibit sending PII. If you need per-recipient tracking, use an opaque ID.
Empty values, whitespace, non-ASCII and over-long values — each creates a value that is hard to filter on, or a blank row that looks like a bug in your reporting.
FAQ
Can I fix the drift retroactively in GA4?
Not in the collected data. You can create a custom dimension or use BigQuery to normalise on read, and Looker Studio can group values with a calculated field — but the raw rows stay split. Fixing the links going forward is the only real remedy, which is why linting before a send is worth the two minutes.
Is lowercase actually required?
Not required, just consistent-or-nothing. Lowercase is the convention because it is the one rule everybody can follow without a lookup table. What matters is that every link for a campaign uses the identical string.
Where do I get a clean set of links?
The bulk UTM builder generates them with lowercasing and hyphenation applied uniformly, which is the other half of this problem — lint what exists, and generate new links in a way that cannot drift.
How do I strip UTMs off a URL entirely?
The UTM cleaner removes them, including click IDs like gclid and fbclid that are not utm_-prefixed.