UTM Cheat Sheet: Values and Where to Click
Values for every channel, the field to put them in on Google Ads, Microsoft Advertising, Meta and LinkedIn, what each email platform writes, and the lookups for links on the way: anatomy, redirects, lead forms, test clicks and changing your taxonomy. Every vendor fact sourced and dated.
On this page
- How to use this page
- Choosing each value
- Source
- Medium
- Campaign
- Term
- Content
- Values by channel
- Google Ads search
- Microsoft Advertising search
- Meta ads
- LinkedIn ads
- Retargeting
- Display
- Newsletter
- Promotional email
- Staff email signatures
- Organic social
- QR code
- Direct mail
- YouTube
- Podcast
- Affiliate and partner
- Webinar or event
- Variant tests
- Ad platforms: where to click
- Google Ads
- Microsoft Advertising
- Meta
- Levels and name limits
- Email platforms
- What each one writes
- Giving every slot one writer
- Where the settings live
- Links on the way
- How platforms change links
- URL anatomy and hygiene
- Sharing
- Keeping links working
- Testing how a builder assembles links
- Capturing UTM values in lead forms
- 1. Keep the values when someone lands
- 2. Add hidden fields to every lead form
- 3. Fill the fields before the form is sent
- Keeping test clicks out
- When a report looks wrong
- Changing your taxonomy
- Before
- Cutover
- Overlap
- Close
- Where links hide
- Changelog entry template
- Mapping table template
- The message for each audience
- Sample close criteria
How to use this page
Find the channel, copy the values, and put them in the field named under the platform. Change the campaign value to your own; the rest is ready to use.
The values follow the book’s conventions (Chapter 3): lowercase, underscores inside a value, hyphens between segments, and campaigns in the [initiative]- pattern. The examples are Stride’s, the book’s fictional shoe brand. Chapter 5 explains who writes each link; this page is the lookup.
Every vendor fact here (a menu path, a setting, a default, a limit, a behavior) carries a link to the vendor’s own documentation and the date we checked it. Vendors move their menus often. When a path has moved, the setting’s name usually hasn’t, so search the settings for it. A fact we couldn’t confirm in the vendor’s own pages isn’t on this page.
Choosing each value
Source
The source is the platform or property that sent the visit: google, facebook, instagram, linkedin, newsletter, promotional_email. Offline, it’s what carries the link: retail_display, direct_mail, print_ad, event. A source may carry one detail segment after its type, naming the third party that publishes the link: partner-acme, affiliate-jane_smith. Where your own printed material sits is a placement, in content. An email platform’s name (mailchimp, klaviyo) is never on the list; Chapter 5 shows where one comes from.
Each medium takes only some sources, so the list holds pairs as well as values. Stride’s: cpc with google; paid_social and social with facebook or instagram; email with newsletter or promotional_email; offline with retail_display. Two listed values can still make a wrong pair: newsletter / social files as Organic Social (Chapter 3).
Medium
The medium comes from one closed list, because analytics sorts visits into channels by it (Chapter 2):
| Medium | Use for | GA4 channel |
|---|---|---|
cpc | paid search | Paid Search |
paid_social | paid social | Paid Social |
paid_video | video ads | Paid Video |
social | organic posts | Organic Social |
video | video descriptions, cards | Organic Video |
email | every email | |
display | display, banners | Display |
affiliate | affiliate links | Affiliates |
referral | partners, event apps | Referral |
audio | podcasts | Audio |
offline | QR codes, print, events | Unassigned |
The paid mediums land in their paid channel with a source of the matching kind (a search engine, a social network, a video site). offline is the deliberate exception: GA4 files it as Unassigned unless you add a custom channel group (GA4 Field Notes).
Campaign
The campaign is the initiative, the same string in every channel that promotes it: spring_sale-runners-2025_03. Every segment is present, with na when one doesn’t apply. The date is the launch, never the end: Stride uses the launch month, and a quarter (2025_q1) is the coarser choice. No platform or channel goes in it: those are source and medium. After a region is added (Chapter 10), the pattern is [region]-, with regions us, uk, europe and north_america.
When a campaign name needs more segments, the values tend to differ by business. Which segments to add, and in what order, is Chapter 4.
| Segment | B2B software | E-commerce |
|---|---|---|
| Initiative | webinar, launch, demand_gen | spring_sale, black_friday, clearance |
| Product | api, analytics | runners, sandals |
| Objective | awareness, conversion, retention | awareness, conversion, retention |
| Date | 2025_03 or 2025_q1 | 2025_03 |
An e-commerce product is a line, not a SKU. Regions are the same plain words in either: us, uk, europe, north_america. An audience goes in utm_term (Chapter 6), or in the campaign as a segment. Running many clients at once is the Agency Playbook.
Term
The term holds the keyword or the audience. In paid social and display it’s the ad set or ad group (Chapter 6), such as retargeting-cart_abandoners; in paid search, the keyword, such as running_shoes. On email, organic posts and QR codes there’s no keyword or audience to record, so it has nothing to hold.
Content
The content value tells apart several links or creatives inside one campaign, source and medium: [placement]-[element], plus -[variant] when testing (hero-image, cta-shop_now, video-testimonial-15sec). On an ad platform it’s the ad (Chapter 6). On printed material it names where the material sits: Stride’s QR code carries fleet_feet_nyc-qr_code, and every display gets its own value (Chapter 5). Content values typed without a pattern split one placement into several rows.
Values by channel
Values only, by slot: the source row is utm_source, and so on. The chapter named beside a value explains why it’s there.
Google Ads search
| Slot | Value |
|---|---|
| source | google |
| medium | cpc |
| campaign | spring_sale-runners-2025_03 |
| term | {keyword} |
| content | {creative} |
Name the Google Ads campaign spring_sale-runners-2025_03 as well: with auto-tagging on, GA4 shows the Google Ads campaign’s name instead of the link’s (Chapter 5), and the name is the join key for spend (Chapter 6). {keyword} and {creative} are ValueTrack parameters, listed under Google Ads below.
utm_source=google&utm_medium=cpc&utm_campaign=spring_sale-runners-2025_03&utm_term={keyword}&utm_content={creative}
Microsoft Advertising search
| Slot | Value |
|---|---|
| source | bing |
| medium | cpc |
| campaign | spring_sale-runners-2025_03 |
| term | {keyword} |
| content | {AdId} |
utm_source=bing&utm_medium=cpc&utm_campaign=spring_sale-runners-2025_03&utm_term={keyword}&utm_content={AdId}
{Campaign} returns the campaign’s name, so it can fill utm_campaign when the Microsoft campaign carries the value. {AdId} is the ad, where Chapter 6 puts it; Microsoft’s own UTM tagging writes the ad group there instead (below).
Meta ads
| Slot | Value |
|---|---|
| source | facebook or instagram |
| medium | paid_social |
| campaign | {{campaign.name}} |
| term | {{adset.name}} |
| content | {{ad.name}} |
Stride’s campaign is named spring_sale-runners-2025_03 and its ad video-testimonial-15sec, so those are the values that arrive (Chapter 6).
utm_source=facebook&utm_medium=paid_social&utm_campaign={{campaign.name}}&utm_term={{adset.name}}&utm_content={{ad.name}}
LinkedIn ads
| Slot | Value |
|---|---|
| source | linkedin |
| medium | paid_social |
| campaign | {{CAMPAIGN_NAME}} |
| term | {{AD_SET_NAME}} |
| content | {{AD_NAME}} |
The same mapping as Meta’s, in LinkedIn’s names; the levels were renamed in October 2025 (below).
Retargeting
| Slot | Value |
|---|---|
| source | instagram |
| medium | paid_social |
| campaign | spring_sale-runners-2025_03 |
| term | retargeting-cart_abandoners |
| content | {{ad.name}} |
Retargeting is an audience, not a medium: the medium is the platform’s paid one, the campaign value is the initiative’s, the same as prospecting, and the audience goes in the term (Chapter 6) or in the campaign as a segment. On Google Ads, the medium is cpc or display.
Display
| Slot | Value |
|---|---|
| source | google |
| medium | display |
| campaign | brand_ |
| content | 300x250-sidebar-version_a |
The source is the network serving the ad. Display bought through Google Ads with auto-tagging on takes its campaign from Google Ads in GA4, as search does (Google, checked 2026-10-06).
Newsletter
| Slot | Value |
|---|---|
| source | newsletter |
| medium | email |
| campaign | spring_sale-runners-2025_03 |
| content | hero-image, cta-shop_now, footer-link |
One content value per link. The campaign is the initiative the issue promotes, the same value as in every other channel.
Promotional email
| Slot | Value |
|---|---|
| source | promotional_email |
| medium | email |
| campaign | spring_sale-runners-2025_03 |
| content | cta-shop_now, banner-hero |
A separate source from newsletter keeps recurring and one-off email apart in a report.
Staff email signatures
| Slot | Value |
|---|---|
| source | email_signature |
| medium | email |
| campaign | the initiative the signature’s link promotes |
| content | signature-sales_team, signature-support_team |
Tagged, signature clicks sit inside Email beside campaign email; filter the source out when you judge campaigns. Untagged, a click from a reply thread arrives with whatever referrer the mail app sends; email apps send none (Chapter 2).
Organic social
| Slot | Value |
|---|---|
| source | facebook, instagram, linkedin, twitter, tiktok |
| medium | social |
| campaign | spring_sale-runners-2025_03 |
| content | post-image, bio-link, story-link_sticker |
social, not paid_social: an organic post belongs in Organic Social.
QR code
| Slot | Value |
|---|---|
| source | retail_display |
| medium | offline |
| campaign | spring_sale-runners-2025_03 |
| content | fleet_feet_nyc-qr_code |
Printed as the short link stride.co/nyc25, whose redirect writes the tagged link (Chapter 5). The content names the display, so every display gets its own value. Several codes on one display add a variant: fleet_feet_nyc-qr_code-window, fleet_feet_nyc-qr_code-counter.
Direct mail
| Slot | Value |
|---|---|
| source | direct_mail |
| medium | offline |
| campaign | spring_sale-runners-2025_03 |
| content | postcard-version_a, catalog-page_3 |
Printed as a short link or a QR code, like the QR code above.
YouTube
| Slot | Value |
|---|---|
| source | youtube |
| medium | video for descriptions, cards and end screens; paid_video for ads |
| campaign | brand_ |
| content | description-link_1, end_screen-cta, card-mid_video |
Podcast
| Slot | Value |
|---|---|
| source | podcast-[show] |
| medium | audio |
| campaign | brand_ |
| content | show_notes-link, spoken-cta |
The show goes in the source’s detail segment: podcast-marketing_over_coffee. A spoken call to action needs an address someone can say: a short path such as stride.com/podcast, redirecting to the tagged link with utm_content=spoken-cta.
Affiliate and partner
| Slot | Value |
|---|---|
| source | affiliate-jane_smith, partner-acme |
| medium | affiliate for affiliates, referral for partners |
| campaign | spring_sale-runners-2025_03 |
| content | sidebar-banner, text_link-review |
When you make the links and hand them out, every affiliate’s values come off your list. When affiliates type their own, each one can add a new spelling.
Webinar or event
The campaign value is the same on every touchpoint; source and medium change with where each one lives. For a webinar, webinar-product_demo-2025_04. For an in-person event, event-sxsw-2025_03 on every link:
- invitation email:
promotional_email/email, contentinvite-cta - speaker announcement:
linkedin/paid_social, contentspeaker-announcement - registration ad:
google/cpc, contentregistration-ad - booth QR codes:
event/offline, contentbooth-main_displayandbooth-demo_station - slides QR in a talk:
event/offline, contentsession-slides_download - event app listing:
event_app-sxsw/referral, contentexhibitor-listing - follow-up and recording emails:
promotional_email/email, contentfollowup-day_2andrecording-link
Follow-up email tagged with the event’s campaign counts toward the event; tagged with another campaign value, its conversions count toward that one instead.
Variant tests
A test run through utm_content works on any channel you tag, and its results land in your analytics beside everything else. Each variant is a content value named for what changed:
| What changes | The variants |
|---|---|
| CTA color | hero-cta-red, hero-cta-blue |
| CTA text | cta-shop_now, cta-see_collection |
| Ad format | video-testimonial-15sec, image-product_shot |
| QR code spot | fleet_feet_nyc-qr_code-window, fleet_feet_nyc-qr_code-counter |
- Change one thing between the variants. The rest of the creative, the audience, the timing and the landing page stay the same.
- Give every variant the same source, medium, campaign and term. Only
utm_contentdiffers. - Name each variant for what changed:
hero-cta-redstill explains the test a year later, andvariant_adoesn’t. - Two tests on the same source and medium at once leave a winner nobody can explain. Run them in sequence, or on different source and medium pairs, which a report keeps apart.
- Read the result: filter to the campaign, source and medium, break the report down by content, and compare sessions, conversion rate and revenue per session.
Ad platforms: where to click
Google Ads
Three fields take tracking parameters (custom parameters, tracking templates, checked 2026-10-06):
| Field | What it does |
|---|---|
| Final URL suffix | adds your parameters to the end of the landing page URL |
| Tracking template | wraps the landing page URL, with {lpurl} standing in for it |
| Custom parameters | up to 8 of your own, used as {_name}; at any level except the account |
Where each lives (Google, URL options, checked 2026-10-06):
- the account: the Admin menu, Account settings, Tracking template
- a campaign: its settings, Additional settings, Campaign URL options
- an ad group: add the Tracking template column to the ad groups table, then edit it with the pencil icon
- one ad: edit the ad and expand Ad URL options
The most specific level wins: keyword, then ad, ad group, campaign, account (Google, checked 2026-10-06). Changes at the account, campaign and ad group levels need no review; changes at the ad, keyword or sitelink level go through review (same page). Changes to tracking templates take 24 to 48 hours to reach ads serving (Google, checked 2026-10-06).
ValueTrack parameters fill in at click time, in single braces (Google, checked 2026-10-06):
| Parameter | Returns |
|---|---|
{keyword} | the keyword that matched the search; blank when an ad matched without one |
{creative} | the ad’s ID |
{campaignid} | the campaign’s ID (no parameter returns its name) |
{adgroupid} | the ad group’s ID |
{matchtype} | e exact, p phrase, b broad, a AI Max keywordless |
{network} | g Google search, s search partners, d Display; ytv, vp, gtv, x and e for YouTube, video partners, Google TV, Performance Max and app engagement |
{device} | m mobile, t tablet, c computer |
{placement} | the site where the ad was clicked |
{loc_physical_ms} | the click’s location, as an ID |
With auto-tagging on, a click carries a gclid (Google, checked 2026-10-06), and GA4 builds source, medium and campaign from Google Ads; your term and content go to the Manual term and Manual ad content dimensions (Chapter 5, GA4 Field Notes).
Microsoft Advertising
The account’s tracking template: from the navigation menu on the left, hover over Campaigns, select Settings, Account level options, then Tracking template (Microsoft, checked 2026-10-06). Custom parameters take up to 8 key and value pairs on campaigns, ad groups, keywords and ads, 3 on sitelinks, and none on the account (Microsoft Learn, help, checked 2026-10-06).
On the same settings page, under Auto-tagging of UTM, Add UTM tags to my destination URLs tags links for you, either replacing all existing tags or keeping yours and adding any that are missing (Microsoft, checked 2026-10-06). On a search campaign it writes:
| Parameter | Microsoft’s value |
|---|---|
| source | bing |
| medium | cpc |
| campaign | the campaign |
| term | the keyword |
| content | the ad group |
Other campaign types get other values (msads and cpm on audience ads, for one), and for some accounts it adds utm_source_platform too, a feature Microsoft is still rolling out (same page). Its content is the ad group, where Chapter 6’s mapping puts the ad.
URL parameters, filled in at click time; they aren’t case-sensitive (parameters, case, checked 2026-10-06):
| Parameter | Returns |
|---|---|
{Campaign} | the campaign’s name |
{CampaignId} | the campaign’s ID |
{AdGroup} | the ad group’s name |
{AdGroupId} | the ad group’s ID |
{AdId} | the ad’s ID |
{keyword} | the keyword |
{QueryString} | the search query the person typed |
{MatchType} | e exact, p phrase, b broad |
{Network} | o Microsoft’s own (Bing, AOL, Yahoo), s search partners, a audience placements |
{Device} | m, t or c |
{msclkid} | Microsoft’s click ID, used for its conversion tracking (Microsoft, checked 2026-10-06) |
Meta
Complete the ad’s creation steps until you reach Tracking. Below it, type the string into the URL parameters field, or click Build a URL parameter, then Apply (Meta, checked 2026-10-06). Meta appends the field to the Website URL, and where the same key appears in both, the field’s value wins (same page).
Dynamic parameters (Meta, checked 2026-10-06):
| Parameter | Returns |
|---|---|
{{campaign.name}} | the campaign’s name |
{{adset.name}} | the ad set’s name |
{{ad.name}} | the ad’s name |
{{campaign.id}}, {{adset.id}}, {{ad.id}} | the IDs |
{{site_source_name}} | fb, ig, msg, an or th (Threads) |
{{placement}} | the placement |
{{site_source_name}} writes fb and ig, not the list’s facebook and instagram, so as a source it adds two spellings.
A name parameter keeps the name the campaign, ad set or ad had when the ad was first published, for that object’s whole life: a rename later doesn’t reach the links, and a new value needs a new campaign, ad set or ad (same page). So the name an object has at launch is the one that arrives.
In Campaign Manager, select Advertise on the left, select the campaign on the Campaigns tab, then on the Ad sets tab move your cursor over the ad set’s name and click Edit (LinkedIn, checked 2026-10-06).
Static parameters can go on the account, the ad set and the ad; dynamic ones on the account or the ad set (LinkedIn, checked 2026-10-06; that page still calls the ad set a campaign, its name before the rename below). The dynamic parameters, in capitals and double braces: {{ACCOUNT_ID}}, {{ACCOUNT_NAME}}, {{CAMPAIGN_ID}}, {{CAMPAIGN_NAME}}, {{AD_SET_ID}}, {{AD_SET_NAME}}, {{AD_ID}}, {{AD_NAME}} (same page).
In October 2025 LinkedIn renamed its levels: the campaign group became the campaign, the campaign became the ad set, and the creative became the ad, and existing ad sets’ parameters updated themselves (LinkedIn, checked 2026-10-06). The Marketing API kept the old names, campaign groups, campaigns and creatives (Microsoft Learn, checked 2026-10-06), so a warehouse table built from the API can say “campaign” where Campaign Manager says “ad set”. Write down which level each export’s columns mean.
Levels and name limits
Every platform here stacks its ads in three levels. The top one’s name equals utm_campaign; the middle one, where the audience is chosen, maps to utm_term; the ad maps to utm_content (Chapter 6).
| Platform | Top, middle, bottom |
|---|---|
| Google Ads | campaign, ad group, ad |
| Meta | campaign, ad set, ad |
| campaign, ad set, ad | |
| TikTok | campaign, ad group, ad |
| X | campaign, ad group, ad |
Sources, checked 2026-10-06: Google, Meta, LinkedIn, TikTok, X API (which calls the ad group a line item).
Name length limits, where the vendor states one:
| Platform | Limit |
|---|---|
campaign names (the API’s campaign group): 200 bytes in UTF-8, which is 200 characters of a-z, 0-9, _ and - (Microsoft Learn) | |
| X | campaign names: 255 characters (X API) |
| Google Ads | campaign and ad group names: 256 characters (Google Ads API) |
| Meta | ad set names: 400 characters; none stated for campaigns or ads (Meta) |
| TikTok | campaign names: 512 characters (TikTok) |
All checked 2026-10-06. One campaign name runs on every platform, so it has to fit the strictest limit among the ones you use. Of these, that’s LinkedIn’s 200 bytes, on the campaign name, the one that must equal utm_campaign.
Email platforms
An email platform can tag links for you. Turned on while you also tag links yourself, it puts two writers on one slot: its value replaces yours, or sits beside it (Chapter 5). Here is what each one writes, where its setting lives, and what its help says about a link you already tagged. “Not stated” means the vendor’s help doesn’t say; send yourself a test and read a clicked link.
What each one writes
Mailchimp (help, checked 2026-10-06):
- source, medium, content: not stated
- campaign: a title you can edit, by default the email’s title combined with the date
- in automation flows only, each parameter can be changed through Modify UTM Parameters
- a link you already tagged: not stated; Mailchimp warns that combining its tracking with your own UTMs “could skew results” and recommends choosing one
HubSpot (traffic sources, tracking settings, checked 2026-10-06):
- source, medium: not stated
- campaign: the campaign the email is associated with;
hs_emailfor a marketing email with none,hs_automationfor workflow emails - content: a value HubSpot reads as the email’s name
- a link you already tagged: your choice of three settings (below)
Klaviyo (help, checked 2026-10-06):
- source: always on; the default isn’t stated (
klaviyois one of the static options) - medium: always on; since June 2, 2025 the default is the message type (
email,sms,push,whatsapp), where it used to becampaignorflow; settings saved before then keep the old values - campaign,
utm_id, term: each can be turned on or off - content: no built-in parameter; up to five custom parameters
- a link you already tagged: not stated
Brevo (help, checked 2026-10-06):
- source: always
brevo, and it can’t be changed - medium: always
email, and it can’t be changed - campaign: the campaign, workflow or template name, which you can edit
- content and term: off by default; when on, one value per message, not per link
- custom parameters: one on Professional, up to ten on Enterprise
- a link you already tagged: not stated
ActiveCampaign (help, checked 2026-10-06):
- source:
ActiveCampaignwith branding on,Newsletterwith branding off - medium:
email - campaign: the campaign name, which you can customize
- content: the email’s subject line
- a link you already tagged: not stated
Giving every slot one writer
Chapter 5 maps the three ways (you, the platform, or both on purpose). Two facts above decide what’s possible here: a platform’s tagging can stand in for yours only where it lets you write every slot your list needs (Brevo’s source is fixed as brevo, and none of these writes a content value per link), and HubSpot’s second setting tags only the links you haven’t. Tagging every link yourself, a recurring newsletter’s content values can sit in the email template by position (header-logo, hero-cta, article_1-read_more, footer-contact), with a merge tag for the campaign so it changes per send.
Where the settings live
Mailchimp
Checked 2026-10-06 (help). For a regular email: in the email builder’s Settings & Tracking section, check Google Analytics link tracking, then save. For an automation flow: Edit Settings, then check Google Analytics link tracking. In a flow, the three dots next to an email action open Modify UTM Parameters, with a dropdown per parameter.
HubSpot
Checked 2026-10-06 (help). Settings (the gear icon), Marketing, Email, the Tracking tab:
| Setting | What it does |
|---|---|
| Add source tracking tags to all URLs | HubSpot’s tags on every link, overwriting yours |
| Add source tracking only if no existing tags in URL | HubSpot tags only the links you haven’t |
| Don’t add source tracking tags | no automatic tagging |
HubSpot’s tracking URL builder is under Settings, Tracking & Analytics, Tracking URLs, Create tracking URL. It makes the tagged URL and a short link, and HubSpot’s help says to use the full link, not the short one, in Google Ads (help, checked 2026-10-06).
Klaviyo
Checked 2026-10-06 (global settings, per message).
- Global settings: your account name (bottom left), Settings, Other, UTM tracking.
- Each parameter: a built-in Klaviyo option or your own static, dynamic or custom value, with different defaults for campaigns and flows.
- A global change reaches every message that uses the global settings; messages with custom UTMs, or with tracking off, keep theirs.
- One campaign: turn on Include tracking parameters, then Customize tracking parameters, or tick Do not use UTM tracking for this campaign.
- One flow: one checkbox turns UTM tracking on, and Use custom tracking parameters sets the flow’s own values.
Brevo
Brevo’s help lists each parameter with whether it’s on by default and whether it can be edited; global settings apply to new campaigns, templates and automation messages (help, checked 2026-10-06).
ActiveCampaign
The account-wide setting is under Settings, Advanced, and a campaign’s name can be changed with Customize on its Campaign Summary page (help, checked 2026-10-06).
Links on the way
A link can change after you paste it: wrapped in a redirect, given an extra parameter, or stripped of its query (Chapter 5 explains the three kinds). These are the lookups for the route between your builder and the address bar.
How platforms change links
| Where | What happens to the link |
|---|---|
| Facebook, Instagram ads | an ad click arrives with Meta’s click ID, fbclid (Meta, checked 2026-10-06) |
| Facebook, Instagram | external links from ads and organic posts open in the in-app browser by default (Meta, checked 2026-10-06) |
| TikTok | visitors may open links in TikTok’s in-app browser (TikTok, checked 2026-10-06) |
| a shared link longer than 26 characters is shortened when you post (LinkedIn, checked 2026-10-06) | |
| X | every link is shortened to a t.co link, with no opt-out (X, read from the archived copy of 2026-09-23 on 2026-10-06; the live page blocks automated reads) |
| Outlook desktop | a URL that Safe Links wraps past Outlook’s 2,084-character limit is truncated; builds 16116.10000 and later raise the limit to 8,192 (Microsoft, checked 2026-10-06) |
| Email security scanners | Proofpoint URL Defense and Barracuda Link Protection rewrite links in email to point at their own redirect (Proofpoint, Barracuda, checked 2026-10-06) |
A scanner’s wrapper makes a long link longer, so a tagged link near 2,084 characters can lose its end in Outlook.
Whatever the platform, the check is the same: click the published post or the sent email, not the raw URL, and read the address bar for every parameter, on a phone as well as a desktop.
URL anatomy and hygiene
A link has up to five parts, always in this order (RFC 3986, section 3). In https://:
- scheme:
https - host:
stride.com - path:
/spring-sale - query, after the
?:utm_source=newsletter - fragment, after the
#:sizes
Tags go before the #
The query starts at the first ? and ends at the first # (section 3.4), and everything after the # is the fragment, which is separated from the rest before the link is followed and read only by the browser (section 3.5). So in stride.com/ the tags are part of the fragment, and the link has no query at all. The working order is stride.com/.
Safe characters in values
a-z, 0-9, _ and - (plus : in Key-Value names, Chapter 4). A space isn’t a character a URL can carry, so it travels percent-encoded as %20 (RFC 3986, section 2.1), and in a query a + is read as a space (WHATWG URL Standard). Underscores between words leave nothing to encode.
Hyphens in paths, underscores in values
Google’s search guidance recommends hyphens rather than underscores to separate the words of a URL (Google Search Central, checked 2026-10-06), so a page reads /spring-sale. That’s the path, the part a search engine reads as words. Tag values follow the book’s own rule instead: underscores inside a value, hyphens between segments (Chapter 3). The path is case-sensitive too: only the scheme and the host aren’t (RFC 3986, section 6.2.2.1).
What the browser’s referrer carries
With no policy set, browsers use strict-: a click from another site sends only that site’s origin (https://m.facebook.com, not the post), and a click from an HTTPS page to an HTTP one sends no referrer at all (MDN, W3C Referrer Policy, checked 2026-10-06). It’s why Chapter 2’s untagged clicks arrive as a bare domain, and why an http landing page gets no referrer from an https site.
Short links
A long tagged URL works, but it’s long to share, it can be cut off (the Outlook row above), and it makes a dense QR code: the more data a code holds, the more modules it needs and the larger the symbol (DENSO WAVE, checked 2026-10-06). A short link fixes the length, and it’s a redirect, so the tags arrive only if the redirect writes them (below). A branded short domain (stride.co/nyc25 rather than a shortener’s random path) tells people whose link they’re tapping. The shortener’s own click counts are its record, not your analytics’.
Tagged pages in search results
A tagged URL is a different URL from the same page untagged. Posted somewhere public, a search engine can find it as a duplicate. A rel="canonical" link on every page, pointing at its untagged URL, tells Google which version you prefer: <link rel=. Google treats it as a strong signal, not a command (Google Search Central, checked 2026-10-06).
Sharing
A link someone pastes into a messaging app, a work chat or a personal email arrives with no tags, and, from an app that sends no referrer, files as direct (Chapter 2). These private shares are often called dark social. Two ways to shrink the blind spot, neither of which closes it:
- Share buttons that add a source per network, such as
utm_source=, so a shared link carries “shared, on LinkedIn” instead of nothing.share- linkedin& utm_medium= social - A “How did you hear about us?” question on your forms, which catches word of mouth no tag can; Chapter 11 sets it beside the other methods that fill the gaps in click tracking.
Keeping links working
A redirect sends the browser to exactly the address it was set up with. The original query doesn’t carry over unless that address includes it; only a missing fragment is inherited (RFC 9110, section 10.2.2). A 301 is no safer than a 302 here. Shorteners, link-in-bio pages, vanity URLs and moved landing pages are all redirects, so:
- Click through the whole chain and read the address bar at the end: the tags have to reach the final page, where analytics reads them.
- When a landing page moves, update the links that point at it, or set up a redirect whose address keeps the query.
- Now and then, click your most-used links and check that each still lands where it should, with every tag on it.
Testing how a builder assembles links
Chapter 9’s five breaks test what a tool refuses; one of them, a landing page that already has a query string, tests how it assembles a link. Three more construction tests belong beside it. Run them in a trial, on your own URLs, and read every link it gives you.
- Spaces and special characters: type a value with a space, or a character outside the safe set above, and check what the tool writes, and whether it lets the value through at all.
- A fragment: start from a URL with a
#and check that the tags land before it. - Volume: if you make links in bulk, make a batch the size of a real launch and check that every row comes out the way the first one did.
Capturing UTM values in lead forms
A form sends only its own fields, so the values a visitor landed with reach your CRM only if the site keeps them and copies them into hidden fields. Chapter 7 explains why; this is the recipe.
1. Keep the values when someone lands
A script reads the UTM parameters from the address and saves them in the browser. Where you save them decides how long they last:
| Where the values are kept | How long they last |
|---|---|
A session cookie (no Expires or Max-Age) | until the browser ends the session; some browsers restore sessions, so it can last longer |
| A persistent cookie | until the date in Expires, or for the period in Max-Age |
| Session storage | until the page session ends |
| Local storage | no expiry, until it’s cleared |
All four belong to one browser on one device, and all four can be cleared. First touch has to survive across visits, so keep it in a persistent cookie or local storage. Last touch is rewritten on every tagged visit.
2. Add hidden fields to every lead form
One per value and per touch. A hidden field isn’t shown on the page and is sent with the form like any other field:
<input type="hidden" name="first_touch_utm_source">
<input type="hidden" name="first_touch_utm_medium">
<input type="hidden" name="first_touch_utm_campaign">
<input type="hidden" name="last_touch_utm_source">
<input type="hidden" name="last_touch_utm_medium">
<input type="hidden" name="last_touch_utm_campaign">
3. Fill the fields before the form is sent
From what step 1 saved. One script does steps 1 and 3:
<script>
(function () {
var KEYS = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'];
var params = new URLSearchParams(location.search);
try {
if (KEYS.some(function (k) { return params.has(k); })) {
var touch = {};
KEYS.forEach(function (k) { touch[k] = params.get(k) || ''; });
// First touch: written once, never overwritten
if (!localStorage.getItem('first_touch')) localStorage.setItem('first_touch', JSON.stringify(touch));
// Last touch: rewritten on every tagged visit
localStorage.setItem('last_touch', JSON.stringify(touch));
}
} catch (e) {}
// Capture phase, so the fields are filled before the form's own handlers read them
document.addEventListener('submit', function (e) {
['first_touch', 'last_touch'].forEach(function (set) {
var saved = {};
try { saved = JSON.parse(localStorage.getItem(set) || '{}'); } catch (err) {}
KEYS.forEach(function (k) {
var field = e.target.querySelector('input[type="hidden"][name="' + set + '_' + k + '"]');
if (field) field.value = saved[k] || '';
});
});
}, true);
})();
</script>
The script listens for submit on the page, so it won’t see a form inside an iframe, or a form sent by a script calling form.submit(), which raises no submit event (MDN, checked 2026-10-06); fill those fields another way, such as when the page loads.
Then give each hidden field a home in the CRM: a field per value and per touch, with the first-touch fields set never to be overwritten once filled. How each CRM does that is in The Tool Landscape.
Cookie lifetimes: MDN, Using HTTP cookies. Storage: MDN, Window.localStorage. Hidden fields: MDN, <input type="hidden">. Checked 2026-10-06.
Keeping test clicks out
Every test click on a tagged link lands in production analytics unless something keeps it out, and in a launch week that noise lands in the first numbers anyone reads. Four ways to keep it out of GA4:
| Method | How |
|---|---|
| Debug mode and a filter | Turn on debug mode with Tag Assistant or preview mode and watch events arrive in DebugView (Admin, Data display, DebugView). Debug-mode events still reach your reports unless a Developer traffic data filter is active (DebugView, data filters, checked 2026-10-06). |
| Internal traffic | Define it (Admin, Data collection and modification, Data streams, your web stream, Configure tag settings, Show more, Define internal traffic), which only labels events with traffic_type. An Exclude data filter (Admin, Data collection and modification, Data filters) keeps them out, from its creation forward and permanently (internal traffic, data filters, checked 2026-10-06). |
| A separate test property | Send test traffic to its own property: the cleanest separation, and the most setup. |
| A test source | Tag test links utm_source=test and leave that value out of your reports, as long as test is never a real value. |
A data filter can run in Testing first, which only marks matching data with the “Test data filter name” dimension, before you make it Active (Google, checked 2026-10-06).
When a report looks wrong
Start with the likeliest cause. Chapter 8’s audit finds most of these as a row that breaks the pattern, or a row no link explains.
| What you see | Check first |
|---|---|
| Campaign traffic missing | tags after a #; a redirect dropping the query; a missing source, medium or campaign |
| One source on several rows | casing and spelling variants; an email platform’s tagging writing beside yours (Chapter 5) |
| The wrong source credited | a tagged internal link (Chapter 8); a platform or redirect rewriting the link |
A lot of (not set) | links shipped without a source, medium or campaign (GA4 Field Notes) |
| Paid clicks in an organic channel | a paid medium the channel rules don’t read as paid (Chapter 2); an untagged ad click |
Changing your taxonomy
A one-page copy of Chapter 10’s four phases. Chapter 10 explains why a change is a period, with old and new formats side by side for as long as the longest-lived link stays in use; this is the checklist.
Before
- Write the change request, tied to the report that needs it.
- Inventory where the values are written (links in the wild, ad platform campaign names, templates) and every system that reads them (analytics and its reports, CRM fields, joins, dashboards).
- Build the mapping table (template below).
- Set the cutover date, for campaigns launching from then.
- Set the close criterion (samples below).
- Update every reader to read both formats, before anything new ships.
Cutover
- Change the tool so it offers only the new pattern and values.
- Write the changelog entry (template below).
- Send the news: link makers, then report readers, then agencies.
- Train link makers on one real campaign: show the approved values and the builder, then tag one campaign end to end (“We’re launching paid social for the fall sale in Europe. Here’s how you’d tag it.”).
Overlap
- Report on one combined view, or mark the break. Two formats mixed with no mark read as one.
- In every audit, check the old format’s share of new clicks.
- For each long-lived link still sending the old format, decide once: replace it or remap it.
Close
- Check the close criterion you set before the cutover.
- Retire the old format from new links, and keep it readable for history.
- Keep the mapping table for good.
Where links hide
The inventory misses these most easily:
- email templates and email signatures
- social bios
- saved ad-platform URL settings (tracking templates, URL parameters)
- printed codes: QR codes and short links on print
- partner sites
- the builder’s own saved templates
Changelog entry template
| Field | Example (Stride’s region change) |
|---|---|
| Version | 2 |
| Takes effect | campaigns launching from 2025_09 |
| What changed | the campaign pattern gains a region: [region]- |
| Mapping | three-segment names: region us, by lookup |
| Made by | Dana |
Mapping table template
| Old value | Becomes | Old data reads as |
|---|---|---|
li | linkedin | remapped: it meant one thing |
social, before the split | social or paid_social | a marked break: it held two meanings |
| a three-segment campaign | four segments, region first | region by lookup: it follows from something recorded |
| no goal recorded | a goal segment | unknown, never a guess |
The message for each audience
- Link makers: what changes on the form, from which date, and one example link in the new format.
- Report readers: the date of the break, what compares across it (the combined view, or the sum), and where the changelog is.
- Agencies: the new values or pattern, the cutover date, and where their links will come from (your builder, or finished links in the brief).
Sample close criteria
- Every old-format click comes from a known, remapped link.
- Every long-lived link in the inventory has been replaced or remapped.
- A full audit cycle with no old-format clicks except from known long-lived links.