UTM Parameters & Campaign Tracking
What UTMs are for
UTM parameters (Urchin Tracking Module — named after the analytics company Google acquired in 2005) are query string parameters appended to a URL that tell an analytics tool where a click came from. They exist because a raw referrer header only tells you the *domain* a visitor arrived from (e.g. instagram.com), not which specific post, ad, or email drove the click. UTMs let you attach structured campaign metadata to any link you control, so that metadata survives the click and lands in your analytics tool's traffic-source dimensions.
The five parameters
There are five standard UTM parameters, and only two are strictly required for GA4 to register a distinct traffic source: utm_source and utm_medium.
- utm_source — the referring platform or publisher (google, newsletter, facebook, partner-blog). Answers 'where did this click come from.'
- utm_medium — the marketing channel category (cpc, email, social, referral, banner). Answers 'what kind of channel was it.'
- utm_campaign — the specific initiative name (fall_sale_2026, q3_webinar_series). Answers 'which effort was this part of.'
- utm_content — differentiates between variants pointing at the same campaign (headline_a vs headline_b, or sidebar_cta vs footer_cta). Used for A/B testing creative within a campaign.
- utm_term — historically used for paid search keyword tracking (utm_term=martech+consultant); largely legacy with the shift to broad match and automated bidding, but still used for manually tagging audience segments in some paid social setups.
https://sadullah.online/services?
utm_source=linkedin
&utm_medium=social
&utm_campaign=q3_martech_launch
&utm_content=carousel_post_v2
&utm_term=utm_source and utm_medium are the minimum
Naming convention governance — the part everyone skips
UTMs are free-text strings, which means without an enforced convention, the same channel fragments into a dozen inconsistent values: Facebook, facebook, FB, fb_ads, Facebook Ads all show up as different rows in a traffic-source report, silently splitting what should be one channel's data across multiple lines. This is the single most common reason marketing analytics data looks unreliable — not a tracking failure, but a governance failure.
The fix is a written naming convention plus enforcement, not just documentation. Effective governance means: always lowercase, a fixed enumerated list of allowed utm_source and utm_medium values (not freeform), a consistent campaign naming pattern (e.g. {quarter}_{initiative}_{audience}), and a shared campaign URL builder (a Google Sheet with dropdowns, or a tool like UTM.io) that every team member uses instead of hand-typing URLs.
Common UTM naming mistakes
| Mistake | Why it breaks reporting |
|---|---|
| Inconsistent casing (Facebook vs facebook) | Most tools treat UTM values as case-sensitive strings — creates duplicate rows |
| Freeform utm_medium values | 'paid', 'cpc', 'ppc', 'paid-search' fragment what should be one channel |
| Tagging internal links | Tagging your own site's internal nav links overwrites the original session source, corrupting attribution |
| Tagging owned email footer links to your own site | Same self-referral problem — resets attribution mid-session |
| No utm_content on multivariate creative | Impossible to tell which ad variant actually drove the conversion |
| Manually typed URLs with no builder tool | Typos (utm_source=linkedIn vs linkedin) silently split data |
How UTMs flow into GA4's traffic_source
When a tagged URL is clicked, GA4's tag reads the query string parameters on page load and writes them into the session's session_source, session_medium, and session_campaign fields as part of that session's traffic-source data, which is also exported to BigQuery inside the traffic_source and collected_traffic_source nested fields on each event. GA4 uses a last non-direct click model by default within its standard channel grouping reports: if a user arrives via a tagged campaign link, then returns later by typing the URL directly, GA4 still credits the original tagged session as the acquiring source for that user, rather than overwriting it with '(direct)/(none)'. This is why 'direct' traffic often looks smaller in GA4 than the raw number of direct visits would suggest.
SELECT
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'source') AS utm_source,
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'medium') AS utm_medium,
(SELECT value.string_value FROM UNNEST(event_params) WHERE key = 'campaign') AS utm_campaign,
COUNT(DISTINCT user_pseudo_id) AS users
FROM `project.analytics_123456789.events_*`
WHERE event_name = 'session_start'
AND _TABLE_SUFFIX BETWEEN '20260801' AND '20260831'
GROUP BY 1, 2, 3
ORDER BY users DESCGA4's Default Channel Grouping can override sloppy UTMs
What's next
Clean UTM data is the raw material every downstream analysis depends on — including A/B tests measuring which campaign variant actually converts better. Understanding how to read those results correctly is the next skill.
Next: A/B Testing & Statistical Significance →
I build these systems professionally.
Whether it's a RAG pipeline, analytics migration, or AI workflow — let's talk.