Are UTM Parameters Case Sensitive in GA4? (And How to Enforce Lowercase)

Yes, UTM parameters are case sensitive in GA4. utm_source=LinkedIn and utm_source=linkedin are treated as two different traffic sources, appearing as separate rows in your acquisition reports. A campaign that drove 1,000 clicks from LinkedIn might show up as "LinkedIn" with 600 sessions and "linkedin" with 400 — two underperforming sources instead of one unified channel. The fix is not a GA4 setting or a retroactive cleanup. It's enforcing lowercase at the point of link generation, which is exactly what mlz build does automatically.

Comparison showing GA4 fragmentation before (two red rows: utm_source=LinkedIn and utm_source=linkedin with 600 and 400 sessions) versus after mlz build enforcement (one green row: utm_source=linkedin with 1,000 sessions unified)

How case sensitivity breaks your GA4 attribution reports

GA4 treats UTM parameter values as exact strings. There is no normalization layer — GA4 does not lowercase values before storing them, and it does not merge rows that differ only by case. Every unique string becomes its own row in the acquisition dimension.

The practical consequence: if your team builds campaign links inconsistently — some using "LinkedIn," some "linkedin," some "LINKEDIN" — you get a separate row in GA4 for each variant. The same channel appears to be driving fewer sessions than it actually is, because the sessions are spread across multiple source values.

This is one of the most common causes of "unassigned" or fragmented channel data in GA4. Marketers see mediocre numbers, attribute them to campaign underperformance, and adjust spend — when the actual problem is a naming inconsistency introduced at link creation time.

The issue affects all five UTM parameters, but it's most visible and impactful on utm_source and utm_medium:

  • utm_source=linkedin vs utm_source=LinkedIn — two rows, split attribution
  • utm_medium=social vs utm_medium=Social — two rows, potentially two channel groupings
  • utm_campaign=q2-launch vs utm_campaign=Q2 Launch — two rows, plus the space encoding issue

Why case sensitivity breaks channel groupings

GA4's default channel groupings assign each session to a channel — Paid Social, Organic Search, Email, etc. — based on utm_source and utm_medium values matching specific patterns. These patterns are lowercase:

  • Organic Social requires utm_medium matching: social, social-network, social-media, sm, social network, social media
  • Paid Social requires utm_medium matching: paid-social, paidsocial, and similar
  • Email requires utm_medium matching: email, e-mail, e_mail, newsletter

If a link uses utm_medium=Social (capital S), GA4 does not match it to the Organic Social channel grouping rule. The session may land in "Unassigned" — even though you clearly tagged it as social traffic. The channel grouping rules expect exact lowercase strings.

This means case inconsistency doesn't just fragment attribution — it can silently misclassify traffic. Sessions that should appear in "Paid Social" show up in "Unassigned" because utm_medium=Paid-Social doesn't match the expected lowercase pattern.

How mlz build enforces lowercase automatically

mlz build normalizes all UTM parameter values to lowercase before generating the tracked URL. You can't accidentally produce a mixed-case UTM link through mlz build — the tool ensures the output always has consistent lowercase values.

Building a LinkedIn paid social campaign link:

mlz build --url "https://example.com/landing" --source "linkedin" --medium "paid-social" --campaign "q2-2026-launch" --format json
mlz build — lowercase-enforced output
{
  "tracked_url": "https://example.com/landing?utm_source=linkedin&utm_medium=paid-social&utm_campaign=q2-2026-launch",
  "params": {
    "utm_source": "linkedin",
    "utm_medium": "paid-social",
    "utm_campaign": "q2-2026-launch"
  },
  "destination_url": "https://example.com/landing",
  "created_at": "2026-04-26T11:00:00.000Z",
  "link_id": "lnk_cd4e8f2a",
  "stored": true
}

Every value in the output params object is lowercase-hyphenated. GA4 will match utm_medium=paid-social to the Paid Social channel grouping rule. There's no normalization step to remember — it's applied at the point of generation.

This also enforces the no-spaces convention: passing --campaign "Q2 Launch 2026" would be normalized to utm_campaign=q2-launch-2026, preventing the URL encoding issues that come with spaces in parameter values (see Why Your UTM Parameters Are Not Working for the full list of space-related failures).

Case sensitivity: what GA4 sees vs. what it should see

What you tagged What GA4 does What you want
utm_source=LinkedIn Creates "LinkedIn" row — separate from "linkedin" utm_source=linkedin
utm_medium=Social Does not match GA4's "social" channel rule → Unassigned utm_medium=social
utm_campaign=Q2 Launch Creates "Q2 Launch" row — separate from "q2-launch"; space may be encoded inconsistently utm_campaign=q2-launch
utm_source=google
utm_source=Google
utm_source=GOOGLE
Three separate rows in GA4 — all showing partial traffic One row: google

Checking existing links for case inconsistencies

If your GA4 reports already show fragmented source data, the links that caused it are in the wild — you can't retroactively fix the historical GA4 data. But you can stop the problem from continuing by auditing any live links and replacing case-inconsistent ones.

For links you have access to, use mlz check to validate that the URL resolves correctly and inspect the UTM parameter values in the query string:

Check a live campaign URL
$ mlz check "https://example.com/landing?utm_source=LinkedIn&utm_medium=Social&utm_campaign=Q2-launch"

{
  "url": "https://example.com/landing?utm_source=LinkedIn&utm_medium=Social&utm_campaign=Q2-launch",
  "valid": true,
  "checks": [
    { "check": "url_format", "status": "pass" },
    { "check": "ssl", "status": "pass" },
    { "check": "resolution", "status": "pass" },
    { "check": "redirects", "status": "pass",
      "details": { "utm_preserved": true } }
  ],
  "status_code": 200
}

The link resolves correctly — "valid": true — but the UTM values in the URL itself still contain mixed case. mlz check confirms the destination is reachable and parameters are preserved through the redirect chain. The case normalization problem must be caught at build time by using mlz build to regenerate the link with lowercase values.

For links currently live in ad platforms, generate new lowercase versions with mlz build and update the ad creatives. GA4 will start receiving clean, lowercase data from that point forward. Historical data with mixed case cannot be altered — but stopping the fragmentation prevents it from compounding.

Before and after: what enforcing lowercase looks like in practice

A team running monthly LinkedIn campaigns for six months with inconsistent casing might see GA4 reports like this:

  • "LinkedIn" — 3,200 sessions
  • "linkedin" — 2,800 sessions
  • "LINKEDIN" — 400 sessions (from a one-off link built manually)

Three separate source rows for the same channel. Each appears to be a mediocre traffic source. No one can tell the actual combined performance is 6,400 sessions from LinkedIn.

After switching to mlz build for all future link generation, GA4 receives a single utm_source=linkedin row for every new session. Historical data stays fragmented, but new campaign data is clean. Over a quarter, the fragmented rows get diluted by clean data and the picture becomes increasingly accurate.

The key insight is that this is a generation-time problem, not a GA4 settings problem. No GA4 configuration, filter, or derived dimension can retroactively merge mixed-case source values into a single dimension. The only fix that works permanently is enforcing lowercase before the link is built — which is what mlz build does by default.

For a broader guide to UTM naming conventions — including the full lowercase + hyphen standard and why it matters beyond case sensitivity — see the UTM Naming Conventions guide.

FAQ

Does GA4 have a setting to make UTM values case-insensitive?
No. GA4 does not offer a case-normalization setting for UTM values. The values are stored as-is, as exact strings, and each unique string creates its own dimension row. This is a deliberate design choice — GA4 trusts that the tagging system provides consistent values rather than performing its own normalization. The solution is upstream enforcement, not a GA4 configuration change.
Can I fix historical mixed-case data in GA4?
No. Once a session is recorded in GA4 with utm_source=LinkedIn, that dimension value is permanent. You cannot retroactively rename it to linkedin. What you can do is create a custom channel group that treats both "LinkedIn" and "linkedin" as the same channel — but this only helps in reports that use the custom channel group, not in the default acquisition dimensions. The only durable fix is preventing new mixed-case data from entering GA4.
Are UTM parameter names case sensitive (not just values)?
Parameter names (utm_source, utm_medium, etc.) are generally case-insensitive at the HTTP level — UTM_SOURCE and utm_source both work. But follow the lowercase convention for names too: the standard is lowercase with underscores, and some analytics tools may handle non-standard casing inconsistently. Values (what comes after the =) are always case-sensitive in GA4.
What happens to GA4 channel groupings when utm_medium is uppercase?
GA4's default channel definitions match on exact lowercase strings. utm_medium=Email does not match the Email channel rule (which expects email). The session may land in "Unassigned" or an incorrect channel. This is different from just having fragmented attribution — it actively misclassifies the channel. Enforcing lowercase with mlz build ensures values match GA4's channel rules.
Does mlz build enforce lowercase for utm_campaign values too?
Yes. mlz build normalizes all parameter values — utm_source, utm_medium, utm_campaign, utm_term, and utm_content — to lowercase-hyphenated format. A --campaign "Q2 Launch" input produces utm_campaign=q2-launch in the output URL. This prevents both case fragmentation and the URL encoding issues that come from spaces in parameter values.

Stop UTM case fragmentation before it reaches GA4

Install MissingLinkz and use mlz build to generate UTM links that are always lowercase — preventing channel grouping failures and report fragmentation from the point of creation.

npm install -g missinglinkz

Free plan: 50 links/month. No credit card. See all commands in the SKILL.md reference.