How to Build UTM Links for GA4

A correct GA4 UTM link needs three required parameters — utm_source, utm_medium, and utm_campaign — plus two optional ones, utm_content and utm_term. GA4 reads those values into the Session source, Session medium, and Session campaign dimensions, so the moment a visitor lands through a tagged link, your reports can answer where the traffic came from (Google Analytics Help: collect campaign data with custom URLs). The catch most people miss: GA4 stores those values exactly as you type them, case included, so Email and email become two separate rows. Get the conventions right once and your channel reports stay clean. Get them sloppy and your traffic fragments across a dozen near-duplicate sources.

What each of the five parameters does

The five UTM parameters split into three required and two optional. Google's own Custom campaigns reference defines them:

  • utm_source (required) — where the traffic came from: google, newsletter, linkedin. Populates Session source.
  • utm_medium (required) — the marketing channel type: cpc, email, referral. Populates Session medium and drives channel grouping (more below).
  • utm_campaign (required) — the specific campaign name: spring_launch, q3_webinar. Populates Session campaign.
  • utm_content (optional) — distinguishes two links to the same destination, such as two button variants in one email. Populates Session manual ad content.
  • utm_term (optional) — paid-search keywords. Populates Session manual term.

Source, medium, and campaign do the load-bearing work. If a value is missing or non-standard, GA4 can't place the visit in the right channel and the session drifts into Unassigned, the subject of why your GA4 traffic shows as Unassigned.

Case and separators are not cosmetic

GA4 treats UTM values as case-sensitive strings. Facebook, facebook, and FaceBook register as three distinct sources, each with its own row and its own slice of sessions. The same applies to mediums and campaign names. Because there is no built-in normalization, the only defense is a convention you actually follow.

Three rules cover most of it. First, pick lowercase and stay there — it is the simplest rule to enforce and matches how most examples in Google's documentation are written. Second, choose one separator and keep it: a hyphen (spring-launch) or an underscore (spring_launch), never both, never spaces. A space in a URL encodes to %20 and produces ugly, error-prone values. Third, keep each value short and descriptive — two to four words. q3-2026-webinar-paid-promo-final-v2 is a value nobody will reproduce by hand next quarter, which is exactly how fragmentation starts.

utm_medium decides your channel grouping

The single most consequential value is utm_medium, because GA4's default channel grouping classifies traffic primarily by matching the medium against built-in patterns (Google Analytics Help: default channel group). Get the medium right and a visit lands in Paid Search, Paid Social, Email, or Referral. Get it wrong and it lands in Unassigned or the catch-all (Other).

GA4's Paid Search and paid channels are matched with the regular expression ^(.*cp.*|ppc|retargeting|paid.*)$. That pattern means cpc, cpm, ppc, retargeting, and anything starting with paid (like paid-social) all qualify as paid — but an invented medium like social-ads or meta does not, and GA4 has nowhere to file it. The practical takeaway: match your medium to how GA4 actually groups channels. Use cpc for paid search, email for newsletters, referral for partner links, and an organic-social value GA4 recognizes rather than a label you made up. This is also why two tools can report the same campaign differently, the theme of why GA4 and Meta numbers don't match.

Building one correct link, step by step

Start with the clean destination URL, then append the parameters with ? for the first and & for each one after:

  1. Destination: https://yoursite.com/pricing
  2. Source: the platform — linkedin
  3. Medium: a GA4-recognized channel — paid_social matches the paid pattern, or use cpc
  4. Campaign: the named effort — q3_pricing_push
  5. Optional content: the creative variant — sidebar_ad

Assembled, that is:

https://yoursite.com/pricing?utm_source=linkedin&utm_medium=cpc&utm_campaign=q3_pricing_push&utm_content=sidebar_ad

For anyone hand-building these, Google ships a free Campaign URL Builder that assembles and URL-encodes the string for you. It does not, however, stop you from typing Cpc one week and cpc the next — the tool encodes whatever you give it.

Governance beats good intentions

The reason UTM hygiene fails in practice is that the values live in human memory. One marketer types google, another types Google, a third types goog, and three weeks later the Paid Search channel is split across rows that should have been one. A shared builder that normalizes input — rather than a wiki page asking everyone to remember the rules — is the only thing that scales past one person. A naming convention is the policy; a builder that enforces it is how the policy survives contact with a deadline. For the policy itself, see the UTM naming convention template.

VibeTraker ships a Campaign-Link Builder for exactly this. It shows a live preview as you type, offers datalist autocomplete drawn from your own past values so you reuse cpc instead of reinventing it, and raises a drift warning — computed with Levenshtein edit distance — when a new value sits one or two characters from an existing one, catching goolge before it spawns a phantom source. Under the hood it normalizes source, medium, and campaign by trim-and-lowercase through a single shared helper, the same normalization VibeTraker applies when it reads metrics back from GA4 and when it extracts the source from your owned, first-party events. A tag you build collapses to the same bucket your reports group by, by construction.

The builder recommends a canonical medium list — cpc, paid_social, display, email, affiliate, referral, organic_social, sms, push, video — as VibeTraker's internal normalization vocabulary. One nuance worth stating plainly: for GA4's channel grouping specifically, the underscore form organic_social may not match GA4's built-in Organic Social rule and can surface as Unassigned. So when your priority is clean GA4 reporting, prefer the medium values GA4 recognizes, and keep the canonical list as your internal rollup. Either way, the principle holds: decide your vocabulary, encode it in a tool, and stop typing campaign values by hand.

Once your links are consistent, the last step is making sure GA4 is actually collecting them — covered in connecting GA4 to VibeTraker.

FAQ

Frequently asked questions

Which UTM parameters are required for GA4?

utm_source, utm_medium, and utm_campaign are required and populate GA4's Session source, medium, and campaign dimensions. utm_content and utm_term are optional and are used to distinguish creative variants and paid-search keywords.

Are GA4 UTM values case-sensitive?

Yes. GA4 stores UTM values exactly as written, so 'Facebook', 'facebook', and 'FaceBook' register as three separate sources. Pick lowercase and use it consistently to avoid splitting one channel across near-duplicate rows.

What utm_medium values does GA4 count as paid?

GA4's default channel grouping matches paid traffic with the regex ^(.*cp.*|ppc|retargeting|paid.*)$, so cpc, cpm, ppc, retargeting, and any value starting with 'paid' (like paid-social) are treated as paid. Invented mediums such as 'social-ads' or 'meta' are not recognized and tend to land in Unassigned.

Why does my GA4 traffic show up as Unassigned or (Other)?

Usually because the utm_medium doesn't match any of GA4's built-in channel patterns, so GA4 has no rule to file the session under. Using GA4-recognized medium values like cpc, email, and referral instead of custom labels keeps traffic in named channels.