UTM Parameters Guide: Campaign Tracking Without Cookies

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.

By Null Agency · Updated September 10, 2026 · Written for anyone tagging campaign links and reading the reports that come back

TL;DR — five parameters, one convention, two very different attribution models

UTM parameters are five query-string tagsutm_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.

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.

What the five UTM parameters actually do

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.

ParameterAnswersExample value
utm_sourceWhich site or platform sent the visitnewsletter, facebook, google
utm_mediumWhat kind of channel that source isemail, cpc, social, referral
utm_campaignWhich specific push this link belongs tofall-sale-2026, product-launch
utm_termWhich paid keyword triggered the ad (search campaigns)web-analytics, utm-tracking
utm_contentWhich specific ad, email variant, or link positionheader-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.

Naming conventions that don't fracture your own reports

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.

Case sensitivity: why "Facebook" and "facebook" become two different rows

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.

Common mistakes worth checking for right now

A few patterns show up often enough to call out by name, each one quietly distorting a report without throwing an error anywhere.

How to build and test a tagged link

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.

  1. Start with the destination URL. Decide exactly which page the link should land on — the specific page, not the homepage, unless the homepage really is the intended landing spot.
  2. Add a question mark, then the parameters. Append ?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.
  3. Apply your naming conventions. Lowercase, hyphens instead of spaces, and values pulled from your shared naming sheet rather than typed fresh each time.
  4. Paste the full link somewhere it will actually be clicked from — the real email send, the real ad platform, the real social post — not just a browser address bar, since some platforms rewrite or wrap outbound links.
  5. Click it yourself in a fresh tab or private window before the campaign goes live, to confirm the URL loads the intended page and didn't get mangled by a link shortener or platform-specific rewriting.
  6. Check your analytics dashboard for the visit. Confirm the source, medium, and campaign show up as expected — this is the point where a typo or a case mismatch is cheapest to catch, before real campaign traffic is split across it.

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.

How attribution actually works once someone clicks the link

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.

Exactly what GhostMetrics stores from a tagged link

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.

See UTM data with no cookies and no consent banner: try GhostMetrics

Cookieless UTM Breakdown$0 forever1 site free$9.99/mo flat Pro

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 demo

FAQ

Do I need all five UTM parameters on every link?
No. utm_source and utm_medium are the two that matter most — they're what tells a report where a visit came from and what kind of channel it was. utm_campaign is worth adding any time you're running something you'll want to isolate in reports later. utm_term and utm_content are optional extras for distinguishing keywords or ad variants within the same campaign; skip them on a simple link rather than force values that don't mean anything.
Does capitalization actually matter in UTM parameters?
Yes, in most analytics tools UTM values are treated as case-sensitive strings, so utm_source=Facebook and utm_source=facebook are recorded as two different sources. That's not a bug, it's just string matching — the fix is picking one casing convention (lowercase is standard) and applying it every time a link is built, ideally from a shared naming sheet.
How does GhostMetrics attribute a visit that arrives with a UTM?
GhostMetrics has no cookies and no visitor ID, so it uses first-touch within the session: the first UTM set it sees in a browser tab is stored in sessionStorage and attached to that pageview and every later pageview and custom event in the same tab, until the tab closes. It does not remember a UTM across a closed tab or a return visit days later — that's the honest trade-off of not tracking people across sessions.
Does GhostMetrics store utm_term and utm_content?
No. GhostMetrics reads and stores utm_source, utm_medium, and utm_campaign only. utm_term and utm_content are not captured, so if you're relying on those two to distinguish keywords or ad creative variants, that breakdown won't show up in the dashboard.
Should I put UTM parameters on my own site's internal links or navigation?
No — UTM parameters are for links that bring someone in from outside your site: ads, emails, social posts, partner sites. Tagging your own nav or internal cross-links fills your reports with a fake internal source. GhostMetrics uses first-touch within the session, so an internal UTM won't overwrite a source it already captured — but if that internal link is what opens a new tab, the fake source becomes that session's first touch and the real one is lost. In last-touch or session-restart models like GA4's, it can overwrite the real source directly.

Keep reading

Cookieless Tracking Explained

What no cookies actually removes

GA4 vs Cloudflare Web Analytics

Two different tools, compared honestly

Website Analytics for Agencies

One login for every client site

GhostMetrics Live Demo

Real UTM Breakdown, real traffic

Disclosure: 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.