UTM link builder
UTM parameters are query-string tags an analytics tool reads to attribute a visit. This builder writes the classic five: source, medium, campaign, content and term. GA4 actually recognises nine, and it treats every value as case sensitive, stating that "utm_source=google is different from utm_source=Google".
How to build a UTM link
Begin with the thing most tagging guides get wrong, this page’s previous version included. Medium alone does not decide the channel. Read GA4’s own default channel rules and several of the ones people care about most take a condition on source as well. Paid Search needs the source to match Google’s list of search sites and the medium to match ^(.*cp.*|ppc|retargeting|paid.*)$. Paid Social needs a social source and the same medium pattern. Organic Search accepts a search source or a medium of exactly organic. Tag a LinkedIn ad as utm_medium=cpc and you will not get Paid Search, because LinkedIn is not a search site; you get Paid Social if the source matches Google’s social list, and Paid Other if it does not.
Some channels genuinely are medium-only, and those are the safe ones to memorise. Affiliates is utm_medium=affiliate, matched exactly, so the plural affiliates misses it. Referral takes referral, app or link. Display takes display, banner, expandable, interstitial or cpm. Email is more forgiving than the rest and matches on either field, accepting email, e-mail, e_mail or e mail in the source or the medium. Anything matching nothing lands in Unassigned, which GA4 describes as "the value Analytics uses when there are no other channel rules that match the event data", and Unassigned is where campaigns go to be quietly forgotten.
Case is the other reliable way to split one campaign into several, and GA4 documents it flatly: parameter values are case sensitive, so Newsletter and newsletter are two different sources sitting in two different rows of the same report. Nothing normalises them afterwards. The lower-case switch on this panel is on by default for that reason, and it also turns runs of whitespace into hyphens, so spring sale becomes spring-sale rather than arriving as spring%20sale.
Five is no longer the whole set. GA4 lists nine campaign parameters: alongside source, medium, campaign, term and content there are utm_id, utm_source_platform, utm_creative_format and utm_marketing_tactic, with the last two documented as not currently reported. The one worth adding by hand is utm_id, a campaign ID that lets GA4 join a manually tagged campaign to imported cost data, which is how a hand-tagged newsletter or sponsorship ends up with a cost per acquisition beside the ad platforms.
A few mechanics of the builder itself. The URL is parsed properly rather than concatenated, so existing query parameters survive, a value you type twice replaces rather than duplicates the parameter, and a fragment stays where it belongs at the end. That last one prevents a common hand-written mistake: appending ?utm_source=x after a #section anchor puts the whole query inside the fragment, where it is never sent to the server and never reaches analytics. Leave a field empty and its parameter is omitted entirely, which is better than emitting utm_term= and creating an empty dimension value.
Finally, the parameters are public. They sit in the address bar, they are copied whenever somebody shares the link, and they are readable by every script and extension running on the landing page. What they do not do any more is travel onward in the referrer: browsers have defaulted to strict-origin-when-cross-origin since 2020, so a click from your landing page to another site sends only your origin, with no path and no query. Even so, naming a campaign after an unannounced product or a client who has not signed is a way of announcing both. Keep the values descriptive and dull.
What people use it for
- Tagging a newsletter send so every click lands in one campaign row
- Keeping medium values consistent across links written by different people
- Telling a header button and a footer link on the same page apart in the report
- Handing a partner or a sponsor a link that credits their traffic properly
- Checking a link someone else built before it goes out
- Re-tagging a link that already carries parameters, without duplicating them
- Tagging a landing page that has a fragment anchor on the end
Questions
Source, medium and campaign in practice. Without a source, Analytics has nothing to attribute the visit to and falls back to referral or direct.
No, and assuming so is the most common tagging error. GA4’s Paid Search and Paid Social rules both require the source to match a list as well as the medium to match a pattern.
Not Paid Search, because LinkedIn is not a search site. It becomes Paid Social if the source matches GA4’s social list, and Paid Other if it does not.
Affiliates on exactly "affiliate"; Referral on "referral", "app" or "link"; Display on "display", "banner", "expandable", "interstitial" or "cpm"; and Paid Other on the paid medium pattern with no source condition.
GA4 matches ^(.*cp.*|ppc|retargeting|paid.*)$, so cpc, cpv, ppc, retargeting and anything starting with "paid" all qualify. Whether it becomes Paid Search, Paid Social or Paid Other then depends on the source.
Because the rule is an exact match on the singular. The plural falls through every other rule and lands in Unassigned.
It is the most forgiving. GA4 matches email, e-mail, e_mail or "e mail" in either the source or the medium, so an email campaign is hard to mis-tag.
GA4 calls it the value used when no other channel rule matches. Traffic there is still recorded but drops out of every channel report, so a campaign in Unassigned looks like it never happened.
Because GA4 does not normalise it, and says so: utm_source=google is different from utm_source=Google. One campaign tagged inconsistently appears as two rows that never add up.
Only the case. Trimming and replacing any run of whitespace with a hyphen happen either way, because a space in a URL arrives percent-encoded and splits the campaign just as surely — so "Spring Sale" becomes Spring-Sale with the switch off and spring-sale with it on.
Yes. GA4 recognises nine: the classic five plus utm_id, utm_source_platform, utm_creative_format and utm_marketing_tactic. The last two are documented as not currently reported.
A campaign ID that lets GA4 join manually tagged traffic to imported cost data, which is how a hand-tagged sponsorship gets a cost per acquisition beside the ad platforms.
Whatever distinguishes two links to the same page in the same campaign: header-cta against footer-link, variant-a against variant-b. It is the only field that lets you tell them apart afterwards.
The paid keyword. Ad platforms usually populate it automatically through auto-tagging, so filling it in by hand is mainly for platforms that do not.
No. A campaign parameter on a link inside your own site is read as a new campaign arriving, which restarts attribution and credits your own page with the conversion. Tag only links arriving from outside.
They are kept. The link is parsed as a URL rather than concatenated, so existing parameters survive and a utm value you set replaces any matching one instead of appending a duplicate.
It stays at the end, where it belongs. Writing the query after a #anchor by hand buries it inside the fragment, which is never sent to the server and never reaches analytics at all.
No, it is left out entirely. An empty utm_term= would create a blank dimension value that clutters the report without meaning anything.
Yes. UTM parameters long predate GA4 and are read by almost every analytics product and most link shorteners, though each has its own channel grouping rules.
Yes. They sit in the address bar and travel whenever somebody shares the link. They are not passed on in the referrer, though: since 2020 browsers default to strict-origin-when-cross-origin, so the next site sees your origin and not the query. Still do not name a campaign after anything unannounced.
Only through duplication, and only if the tagged URLs get indexed. A self-referencing canonical on the landing page settles it, which is standard practice anyway.
It reads better and most shorteners preserve the parameters through the redirect. Check yours: a shortener that strips the query defeats the whole exercise.
No. The link is assembled in your browser and nothing is sent anywhere.