UTM Parameters Explained: Build, Parse and Track UTM Links in Google Analytics 4
UTM parameters are tags added to the end of a URL, such as `?utm_source=newsletter&utm_medium=email&utm_campaign=autumn_sale`, so that analytics tools know where a visitor came from. They do nothing on the page itself; Google Analytics reads them on arrival and files the session under that source, medium and campaign. Building them takes seconds. Keeping them consistent enough that reports make sense, and parsing them correctly in your own code, is where most teams go wrong.
The UTM parameters and what GA4 does with them
utm_source where the traffic comes from newsletter, google, facebook, partner-site (required)
utm_medium the type of channel email, cpc, social, referral, affiliate (required)
utm_campaign the campaign or promotion autumn_sale, product_launch_2026 (required)
utm_term paid search keyword json+formatter
utm_content which link or creative header_button, footer_link, banner_b
utm_id campaign ID, joins cost data q3-2026-042
utm_source_platform buying platform search_ads_360
utm_creative_format creative type (accepted, not yet reported in GA4)
utm_marketing_tactic targeting (accepted, not yet reported in GA4)
Google's documentation says to always use at least utm_source, utm_medium and utm_campaign. With only a source, GA4 cannot place the session in a meaningful channel. utm_content is the most underused parameter: it tells you which of several links in the same email or page was clicked.
https://devtoolgrid.com/tools/json-formatter
?utm_source=newsletter
&utm_medium=email
&utm_campaign=2026_09_dev_tips
&utm_content=hero_button
utm_medium decides the channel
GA4 groups traffic into channels such as Email, Paid Search, Organic Social and Referral using its default channel group rules, and those rules read utm_medium (with the source). Use the values GA4 expects, or your campaign ends up in "Unassigned".
channel in GA4 utm_medium values it recognises (examples)
Email email, e-mail, e_mail, e mail
Paid Search cpc, ppc, paidsearch (with a search engine as source)
Paid Social cpc, ppc, paid (with a social network as source)
Organic Social social, social-network, social-media, sm
Affiliates affiliate
Display display, banner, cpm
Referral referral
Values are case-sensitive: utm_source=Newsletter and utm_source=newsletter appear as two different sources. Agree on a naming convention, lower case with underscores or hyphens, and write it down before the first campaign.
Building UTM links
Google's Campaign URL Builder (in GA Dev Tools) fills in the fields for you. For campaigns with many links, a shared spreadsheet or a small script keeps the naming consistent across the team. Always encode the values, because spaces, & and # in a campaign name break the URL.
function utmUrl(base, params) {
const url = new URL(base);
for (const [key, value] of Object.entries(params)) {
url.searchParams.set(`utm_${key}`, value.trim().toLowerCase());
}
return url.toString();
}
utmUrl('https://example.com/pricing?plan=pro', {
source: 'newsletter', medium: 'email', campaign: 'Autumn Sale', content: 'hero_button',
});
// https://example.com/pricing?plan=pro&utm_source=newsletter&utm_medium=email&utm_campaign=autumn+sale&utm_content=hero_button
URLSearchParams keeps existing query parameters and encodes values for you, using + for spaces. Putting UTM parameters after a # fragment does not work, because the fragment is never sent to the server and most analytics setups ignore it.
Parsing UTM parameters from a URL
To read UTM values yourself, for example to store the original source with a sign-up or to debug a campaign link, parse the query string with a real URL parser rather than a regex.
const params = new URL(location.href).searchParams;
const utm = Object.fromEntries(
[...params].filter(([key]) => key.startsWith('utm_'))
);
// { utm_source: 'newsletter', utm_medium: 'email', utm_campaign: 'autumn sale' }
from urllib.parse import urlsplit, parse_qs
qs = parse_qs(urlsplit(url).query)
utm = {k: v[0] for k, v in qs.items() if k.startswith('utm_')}
Store the first-touch UTM values when a visitor arrives, in a first-party cookie or in the sign-up form, if you want to know which campaign brought a customer weeks later. Analytics tools attribute sessions, not people, and long consideration cycles lose the original source.
Mistakes that break attribution
Tagging internal links. A UTM link from your own homepage to your pricing page overwrites the real source of that visit. Use UTMs only on links from outside your site: emails, ads, social posts, partner sites and QR codes.
Adding UTMs to Google Ads links while auto-tagging is on. Google Ads adds a gclid parameter automatically, and GA4 uses it to import campaign, keyword and cost data. Manual UTMs on the same links can conflict with it. Leave auto-tagging on and tag only non-Google traffic manually.
Losing parameters in redirects. A short link, a http to https redirect or a login wall that rebuilds the URL without the query string drops the UTMs, and the visit shows as direct traffic. Click every campaign link before launch and check that the UTMs survive to the final page.
Inconsistent names. Newsletter, newsletter, news-letter and email_newsletter split one source into four rows. Pick one form and validate links before they go out.
Personal data in UTMs. Values end up in analytics, logs and referrer headers, so never put an email address or user ID in a UTM parameter.
Finding UTM campaigns in GA4 reports
In GA4, tagged visits appear under Reports › Acquisition › Traffic acquisition, which is session-scoped. Switch the primary dimension to "Session campaign" or "Session source / medium" to see each UTM value. The User acquisition report shows the "First user" versions of the same dimensions: the campaign that first brought each user, which is the view to use for sign-up and customer acquisition.
"(not set)" in the campaign column usually means the visit had no utm_campaign, or the parameters were lost in a redirect. "Unassigned" in the channel column means GA4 could not match the source and medium to a channel rule; check the spelling of utm_medium first. New UTM values can take up to 24–48 hours to appear in standard reports, so use the Realtime report to confirm a test link was recorded.
UTM links in QR codes and offline campaigns
Printed QR codes, flyers and radio mentions have no referrer, so without UTMs their traffic looks like direct visits. Tag the URL behind the QR code (utm_source=flyer&utm_medium=print&utm_campaign=…), and put it behind a short redirect on your own domain, so the QR code stays small and you can fix the link after printing.
Sources and further reading
Google Analytics Help documents the supported UTM parameters, case sensitivity and the requirement to use source, medium and campaign ("URL builders: Collect campaign data with custom URLs"), as well as the GA4 default channel group rules and Google Ads auto-tagging. The WHATWG URL Standard defines URL and URLSearchParams, and the Python urllib.parse documentation covers parse_qs.
Frequently asked questions
What are UTM parameters?
Tags added to a URL's query string, such as `utm_source`, `utm_medium` and `utm_campaign`, that tell analytics tools where a visit came from. They do not change the page; Google Analytics reads them when the visitor arrives.
Which UTM parameters are required?
Google recommends always using `utm_source`, `utm_medium` and `utm_campaign`. `utm_term`, `utm_content` and `utm_id` are optional but useful for paid keywords, individual links and cost-data imports.
How do I build a UTM link?
Use Google's Campaign URL Builder or a script that appends the parameters with `URLSearchParams`, so values are encoded correctly. Keep values lower case and consistent, and test the final link.
Are UTM parameters case-sensitive?
Yes. `utm_source=Google` and `utm_source=google` are reported as different sources in GA4, so choose one convention, usually lower case, and stick to it.
Should I use UTM parameters on internal links?
No. A UTM link between pages of your own site overwrites the visit's real source and campaign. Tag only links that bring visitors from outside.
How do I read UTM parameters in JavaScript?
Use `new URL(location.href).searchParams.get('utm_source')`, or filter all parameters starting with `utm_`. Avoid regex parsing, which breaks on encoded values.