Five parameters, one naming convention, and a surprising number of ways to quietly break your own reports. Here's what UTMs actually do, how to tag a link correctly, and how attribution differs once cookies leave the picture.
UTM parameters are five query-string tags — utm_source, utm_medium, utm_campaign, utm_term, utm_content — appended to a URL so an analytics tool can tell you where a visit came from. They only work if you're consistent about how you write them.
utm_source=Facebook and utm_source=facebook are recorded as two different sources in most tools.utm_source, utm_medium, utm_campaign — using sessionStorage for first-touch within the tab, never cookies. utm_term and utm_content are not captured.Skip to the section you need: the parameter reference table, the build-and-test how-to, or how attribution actually works once you tag a link.
UTM (Urchin Tracking Module — the name survives from a tool Google acquired in the mid-2000s) parameters are just query-string key/value pairs appended to a URL. Nothing about them is special to browsers or servers; they exist purely so an analytics tool reading the landing URL can log where the visit came from. Every UTM parameter is optional in the sense that a broken link still loads the page — but a link with no utm_source falls back to whatever the tool can infer from the referrer — a referral or search bucket at best, "direct" or "(not set)" at worst, which defeats the point of tagging it.
| Parameter | Answers | Example value |
|---|---|---|
| utm_source | Which site or platform sent the visit | newsletter, facebook, google |
| utm_medium | What kind of channel that source is | email, cpc, social, referral |
| utm_campaign | Which specific push this link belongs to | fall-sale-2026, product-launch |
| utm_term | Which paid keyword triggered the ad (search campaigns) | web-analytics, utm-tracking |
| utm_content | Which specific ad, email variant, or link position | header-cta, variant-b |
In practice, utm_source and utm_medium do most of the work — together they tell a report "this visit came from the newsletter, via email" rather than a bare "newsletter." utm_campaign is what lets you pull every link from one push into a single row in a report, regardless of which source or medium sent each individual click. utm_term and utm_content are the fine-grained pair, useful when you're running several variants of the same campaign — two ad creatives, two email subject lines, two link placements — and need to know which one actually pulled the click.
UTMs are just strings, which means an analytics tool has no idea that newsletter and Newsletter and email-newsletter are meant to be the same thing. Every one of those becomes its own row in a report, and one real channel gets split into two or three smaller rows, none of which looks significant on its own. The fix isn't clever — it's discipline, enforced the same way every time a link gets built.
Lowercase everything. Pick lowercase as the default before you tag your first link and never deviate, because mixed casing is the single most common way teams fracture their own source data (more on this below).
Use hyphens, not spaces or underscores. A raw space in a query-string value gets URL-encoded to %20 or a literal + depending on how the link was built, which means the same campaign name can render two different ways depending on who copy-pasted it. Hyphens survive URL encoding cleanly and read fine in a report: fall-sale-2026, not fall sale 2026.
Use a consistent vocabulary for mediums. Decide once whether email campaigns are tagged email or newsletter or e-mail, and reuse that exact value everywhere. The same goes for social vs. social-media, or cpc vs. paid vs. ppc — any of these is fine as a standard; having three of them in rotation is not.
Keep a shared naming sheet. The moment more than one person builds tagged links — a founder and a contractor, a marketer and an agency — a shared reference listing the approved utm_source/utm_medium values and current campaign names stops drift before it starts. Five minutes of setup saves weeks of reconciling split-up data later.
This is worth its own section because it's the single most common way UTM data quietly breaks, and it's invisible until you're staring at a report wondering why your biggest channel looks smaller than it should. Analytics tools generally treat UTM values as literal strings, and GhostMetrics does not normalize case at all. utm_source=Facebook and utm_source=facebook are not merged into one row — they're two separate sources, each with its own visit count, splitting what was really one channel into two smaller, less useful ones.
It happens easily: one team member capitalizes the platform name because that's how you'd write it in a sentence; an ad platform's link builder defaults to a different case; a copy-paste from an old campaign carries over whatever casing was used months ago. None of these are wrong syntactically — a URL with utm_source=Facebook works exactly the same as one with utm_source=facebook when a visitor clicks it. The values just don't reconcile downstream.
The fix is the same lowercase-everything rule from the naming section, applied specifically at the point a link is built. If you're auditing an existing report and see a channel split across cased variants, that's usually the explanation — not two channels, one channel reported as two.
A few patterns show up often enough to call out by name, each one quietly distorting a report without throwing an error anywhere.
%20 or + depending on the tool that built the link, so the same campaign can render two ways. Use hyphens instead.utm_source reports the source but leaves the channel type blank, making it hard to tell a paid click from an organic mention later.fall-sale-2026-women-25-34-variant-b-retarget) is unreadable in a report table and usually duplicates what utm_content or utm_term are for.None of this requires a tool beyond a text editor, though plenty of UTM builders exist if you'd rather not assemble the query string by hand.
?utm_source=... and join any additional parameters with &. If the destination URL already has a query string, use & for the first UTM too — a second ? makes the whole thing one malformed parameter and every UTM on the link is silently ignored.A correctly tagged link looks like this:
https://example.com/pricing?utm_source=newsletter&utm_medium=email&utm_campaign=fall-sale-2026
That's a link for a pricing page, sent from a newsletter, via the email medium, as part of the fall-sale-2026 campaign — three parameters, all lowercase, hyphenated, no spaces. Add utm_term or utm_content only if you're running a search campaign or A/B-testing creative and actually need that level of detail.
Tagging the link correctly only gets you halfway there — what happens after the click depends entirely on how the analytics tool receiving that visit handles attribution, and this is where GA4 and cookieless tools genuinely diverge, not just in privacy posture but in what a report can tell you.
GA4's model is cookie-based and multi-session. GA4 sets a first-party cookie (_ga) that persists across visits, so it can recognize the same browser returning days or weeks later and stitch multiple sessions into one user journey. That's what powers GA4's multi-touch and cross-session reporting — a visitor who clicked a Facebook ad on Monday and converted after a direct visit on Thursday can, in principle, be traced back to that Monday ad. It's also why GA4 needs consent in the EU/UK: that persistence is exactly what consent frameworks are regulating.
GhostMetrics uses session first-touch instead. With no cookies and no persistent visitor ID, there's nothing to recognize a returning browser with. Instead, the first UTM set seen in a browser tab is written to sessionStorage and attached to every pageview and custom event that happens in that same tab, for as long as the tab stays open. Close the tab and that stored UTM is gone — a returning visit days later starts over as untagged, with no memory of the original campaign. Other cookieless tools reach a similar outcome — no cross-session attribution — but each does it its own way; check the docs for the one you use.
This is a real trade-off, worth stating plainly: you lose returning-visitor attribution and multi-session journeys entirely. Someone who clicks a campaign link, doesn't convert, and comes back organically three days later to sign up will not have that signup credited to the original campaign. What you gain is that nothing about the visitor persists once the tab closes — no identifier survives to be correlated across sessions, and GhostMetrics on its own doesn't trigger the consent requirement GA4's cookie does — though anything else on the page that sets cookies still might, and the data GhostMetrics does have is exactly what it appears to be, nothing more. For a fuller look at what "no cookies" removes from a tracking stack, see our cookieless tracking explainer.
Being specific here matters more than being reassuring. GhostMetrics's gm.js reads three of the five UTM parameters from the landing URL — utm_source, utm_medium, and utm_campaign — and stores those. utm_term and utm_content are not captured at all. Keyword-level or ad-variant-level performance won't show up in the dashboard; a breakdown by source, medium, and campaign will.
The dashboard surfaces this as a UTM Breakdown table — source, medium, campaign, and visit count, as a straightforward list you can scan for which campaigns actually drove traffic in a given period. It sits alongside a referrers view and a source types breakdown (search, social, direct, referral) built from the same visit data, so an untagged organic or referral visit still lands in a sensible bucket even without a UTM attached.
The session-scoped UTM also reaches custom events, not just pageviews. Add data-gm-event="signup-click" to a button, or call window.ghostmetrics.track('signup-click', { section: 'pricing' }) from code, and that event carries whatever UTM was first seen in the session — which is what makes "how many signup-clicks came from the newsletter campaign" answerable without a cookie or a visitor ID. See how to track custom events without Google Analytics for more, or our guide to measuring website traffic for the rest of the dashboard.
If multi-session, returning-visitor attribution genuinely matters — long consideration cycles, ad platforms that need conversion data fed back to them — GA4's cookie-based model is built for that, and no cookieless tool replaces it honestly; our Google Analytics alternatives roundup covers where GA4 still wins. If a cookieless read on which campaigns drove which sessions is enough, that's what session first-touch is built for.
GhostMetrics is cookieless web analytics — no cookies, no localStorage, no IP addresses stored, no cross-session identifier. Install one script tag in your <head> and it's live: no plugin, no tag manager, no build step. The free plan is free forever: one site, unlimited pageviews, real-time dashboard, every view, full history — including the UTM Breakdown table.
Raw event export as CSV or JSON is available on every plan, including free — your UTM data is never locked behind an upgrade. Need more than one site, or a public shareable dashboard? Pro is $9.99/mo flat, unlimited pageviews, unlimited websites, with a 30-day free trial — a card starts the trial, nothing is charged for 30 days, cancel anytime.
Start free — see your UTM Breakdown See the live demoDisclosure: GhostMetrics is built by Null Agency and we use it on this site, so we're not a neutral party about our own product — we've kept the claims to exactly what it stores and how attribution works, and said plainly what cookieless, session-based attribution loses compared to GA4's cookie-based model. UTM naming conventions here reflect common practice, not a formal standard; adapt them to your own team's needs.