Pink blossom photographed with a spinning blur against pale blue sky, suggesting campaign labels that smear when UTM names do not match

Shopify UTM Parameters: Campaign Tracking That Stays Clean in GA4 and Shopify

Shopify UTM Parameters: Campaign Tracking That Stays Clean in GA4 and Shopify

Nov 5, 2026

Octavian Contis 10 minutes

Share

Finance asks which campaign paid for Tuesday's order, and the two reports give two different answers. We see this on almost every Shopify stack audit. GA4 Session campaign says spring_sale, while Shopify Analytics says BFCM Email 14 with a string of digits that Messaging stamped on by default.

Both reports are honest about the click they saw.

The labels simply came from different places. The fix is what we call the naming sheet: one approved list that owns utm_source, utm_medium, and utm_campaign, copied exactly by Shopify Messaging and Campaigns, kept off internal links, and checked on the checkout URL after a test click.

Shopify's own UTM guide covers how to build a tagged URL. The gap on live stores is who gets to name things. Messaging, Campaigns, Klaviyo, paid-social macros, and a teammate's bio link will each invent a campaign string unless one convention is locked first.

Every tool already names your campaigns

Shopify Messaging includes a UTM link by default. Growth, Campaigns will mint shareable links, short links, and QR codes. GA4 will read whatever landed in page_location. So the real choice is whether those tools keep their factory labels, or whether the naming sheet is the only writer allowed to name a campaign.

Leave the defaults alone and you get three honest reports that refuse to add up. Messaging writes shopify_email / email / Email name + activity ID. A Meta ad writes facebook / paid_social / Spring Sale 2026. A shortener that strips query strings delivers a session with no campaign at all, and finance ends up asking why GA4 Session campaign and Shopify's Performance by UTM campaign crown two different winners for the same week.

Brands with more than one email tool feel this first. Lanoguard sits on Shopify 2.0 with Klaviyo as a documented partner, so a spring send can leave Messaging with one campaign string and Klaviyo with another unless both teams copy from the same row. Catalogue-heavy storefronts such as RTR Vehicles add dealer referrals and paid social on top, which gives a title-case typo more places to split a row.

What goes on the naming sheet

Google recommends setting utm_source, utm_medium, and utm_campaign together on every manually tagged campaign link. Those three fields populate Session source, Session medium, and Session campaign in GA4 Traffic acquisition, and they are the strings Shopify reads when traffic arrives with utm_campaign in the URL. Write one row per live channel and approve the value before anyone pastes a URL.

ParameterWhat it namesGA4 session dimensionShopify surfaceLocked example
utm_sourcePlatform or publicationSession source / Session manual sourcePerformance by UTM campaign, Growth attributioninstagram, klaviyo, shopify_email
utm_mediumChannel or traffic typeSession mediumMarketing channel and traffic type splitsemail, paid_social, qr_code
utm_campaignThe promotion, same across channelsSession campaign / Session manual campaign namePerformance by UTM campaign, Sales attributed to marketingspring_sale_2026
utm_content (optional)Creative or placement inside that campaignSession manual ad contentCampaigns auto-match may ignore extra paramshero_video_v1
utm_term (optional)Paid keyword you suppliedSession manual termSupported on Campaigns auto-matchrust_protection

Three formatting rules belong on the same page. Use lowercase letters, digits, and underscores only, because GA4 treats Pinterest and pinterest as two sources and Shopify groups on the exact string, so BFCM and bfcm split Performance by UTM campaign the same way. Approve one value per platform, since facebook, fb, and facebook.com are three sources and spring_sale, Spring Sale, and spring-sale are three campaigns. Keep the campaign name identical across email, paid social, SMS, and QR, changing only source and medium so the promotion stays one row.

Add utm_content only when the first three fields stay fixed and you are comparing two creatives or two placements. Google's URL builder docs use it for two links in the same email, and Shopify Campaigns help uses red_banner_v1 against blue_banner_v2. Keep it as an optional column.

Customer names, emails, and phone numbers stay out of every value. GA4 collects the landing URL, so a personal detail in a tag travels with the hit.

A missing field writes (not set) on the matching GA4 dimension. A link with source and no medium still creates a session, and Session medium then sits in (not set), which makes the weekly compare against Shopify look like a hole. Write all three required fields every time.

If an ad platform offers utm_campaign={{campaign.name}}, resolve that macro against the naming sheet before the ad goes live. Title-case names from Ads Manager will split the lowercase Shopify row you already created.

Make Messaging and Campaigns copy it

The naming sheet only works once Messaging and Campaigns stop writing their own strings.

Messaging

Open Apps, Messaging, Settings and read the UTM tracking block. Shopify Help documents the factory values as utm_source=shopify_email, utm_medium=email, and utm_campaign set to the email name plus the activity ID. That campaign default causes most of the splits we find, because nobody in finance named a promotion Welcome series 883421 and Messaging wrote it anyway.

Edit the shop-level values so new sends copy the sheet, then open the next campaign and use Edit UTM parameters if that send needs a different campaign name. Shopify says a settings change applies to new campaigns only, and drafts and already-created emails keep the old tags. Plan the cutover for the next send and leave last week's report as it is.

Keep utm_source=shopify_email when Messaging is the only email tool. If Klaviyo or another ESP already uses klaviyo as source, put that value on the sheet and keep Messaging traffic under shopify_email so the two tools stay on separate rows. Medium stays email in both cases.

Shopify also warns that Messaging conversion counts come from store data and will differ from a third-party analytics tool that only sees link clicks. Use Messaging's own email report for opens and clicks, and let the shared UTM values keep GA4 Session campaign and Shopify Performance by UTM campaign naming the send the same way.

Campaigns

Go to Growth, Campaigns and create the campaign using the sheet's utm_campaign value as the name you intend to report. Under Shareable links, add the destination and the remaining UTM parameters before you copy the full URL, the short link, or the QR code.

Shopify attributes every visit from a shareable link to that campaign, and auto-match rules can pull in traffic that already carries the same utm_campaign and utm_source. Help Centre's example matches utm_campaign=elle and utm_source=facebook, then ignores extra landing parameters such as utm_content. If you rely on auto-match, write the rule from the sheet and expect content-level splits to show up in GA4 only.

Leave a short link alone once people have used it. Changing the handle sends later visits to an error page, and deleting a shareable link removes its traffic from the campaign report. Add a new link when you need a new source or a new QR.

Headless and Hydrogen stores cannot create or edit shareable links. Those builds need the tagged full URL in the ad manager, plus an auto-match rule if you still want Campaigns to collect the sessions.

After the first send, open Analytics, Reports and pull Performance by UTM campaign for the same dates you used in GA4. Shopify's October 2026 UTM article still names that report, and Analytics also ships Performance by marketing campaign, which groups by campaign first and then by channel. Check the attribution model before you argue with finance. Last non-direct click is the Shopify default, and it will differ from a GA4 exploration that uses last click or data-driven credit.

For a single order, open conversion details and choose View full sessions. It is the fastest way to see which UTM values actually landed.

Shopify's UTM article says to tag campaign links you share outside the website. Hold to that line.

Theme navigation, collection filters, product cards, cart buttons, and homepage tiles should stay untagged. A new utm_source on an internal hop starts a fresh campaign session in GA4 and can overwrite the paid or email label before the shopper reaches checkout, so the order ends up looking direct, or like a collection click you invented.

Affiliate and collab links are off-site, so they get tags. Preserve the partner's existing query parameters and append UTMs with & when the destination already has a query string. Fragments that start with # go after the query.

Click it yourself before you print it

A tidy naming sheet still fails if the shortener, the QR encoder, or a redirect drops the query string. Shopify's UTM article is blunt here: test the complete journey before you print a code or paste a short link.

We check four stops on that walk. First, the landing URL in the browser still shows all three required parameters after every redirect. Second, GA4 Realtime or DebugView shows those values on the landing page_view page_location. Third, the checkout URL has kept the campaign and not picked up a new internal tag. Fourth, the test order's conversion details, under View full sessions, still list the sheet's source, medium, and campaign.

Google notes that Realtime and DebugView do limited attribution, and Traffic acquisition can take 24 to 48 hours to show the finished Session source / medium and Session campaign. Shopify marketing metrics can take up to 24 hours. Book the compare for the next working day, on the same date range, with the attribution model written down.

Which setup fits your store

One email tool, mostly Messaging

Keep utm_source=shopify_email and utm_medium=email, then replace the campaign default with the sheet's promotion name, such as spring_sale_2026, before the next send. Leaving Messaging to join the email title and activity ID is how last week's report grew a second row.

Messaging plus Klaviyo or another ESP

Give each tool its own source on the sheet, shopify_email and klaviyo, with the same campaign name and medium staying email. Finance can then split volume by tool without splitting the promotion.

Fix utm_campaign first, then change only source and medium, such as instagram / paid_social and shopify_email / email, and put creative tests in utm_content. With Campaigns auto-match on, Shopify may roll those creatives into one campaign row while GA4 still splits on content.

Build the full tagged URL first, encode that URL into the QR or the shortener, and test the scan on a phone that has never opened the store. Add a new shareable link for a second physical placement, and leave the handle of a code already printed alone.

Headless or Hydrogen

Skip Campaigns shareable links on these builds, put the tagged full URL in the ad platform, and add an auto-match rule if you still want Growth, Campaigns to collect the sessions.

Back to Tuesday's order

When finance asks again, GA4 Session campaign and Shopify Performance by UTM campaign should both say spring_sale. Put the naming sheet in place before the next send.

If several tools already write campaign strings, or a redirect is eating the query before checkout, we can walk the live links as part of a stack assessment or through integrations and system optimisation. Bring the current Messaging UTM settings, one Campaigns shareable link, and a GA4 Traffic acquisition export for the same week.

Frequently Asked Questions

Set utm_source, utm_medium, and utm_campaign on every link you share outside the store. Google Analytics 4 maps those three values to Session source, Session medium, and Session campaign in Traffic acquisition. Add utm_content only when you need to compare two creatives or two placements inside the same campaign, and add utm_term when you are tagging a paid keyword yourself. Leave personal names, emails, and phone numbers out of every value, because GA4 stores the full landing URL.

Shopify Messaging writes a shop-level UTM link by default. Help Centre documents utm_source=shopify_email, utm_medium=email, and utm_campaign as the email name plus the activity ID. You can change those values under Messaging, Settings, or on one campaign when you create the send. Edits apply to new campaigns only, and each value must stay at or under 100 characters.

Each system reads the string that arrived on the landing URL. Messaging can stamp Email name + activity ID while paid social writes spring_sale and a teammate types Spring Sale into a bio link. GA4 treats those as separate Session campaign rows, and Shopify Analytics splits the same way in Performance by UTM campaign. A shared lowercase sheet, plus an override of Messaging and Campaigns defaults, keeps both reports on one name.

No. Put UTM tags on links you share off-site: ads, email, SMS, QR codes, influencer bios, and printed inserts. An internal collection or product link that carries a new utm_source starts a fresh campaign session in GA4 and can overwrite the first-touch label before checkout. Theme navigation, product cards, and cart buttons should stay clean so the landing tag is the one that reaches the order.

Yes. Google Analytics treats Pinterest and pinterest as two sources, and the same split happens for campaign names. Shopify Analytics also groups on the exact string, so BFCM and bfcm become two rows in Performance by UTM campaign. Lock lowercase letters, digits, and underscores on the naming sheet, then reject any ad-platform macro that writes a title-case name you did not approve.

Google says a missing UTM field writes (not set) on the matching session dimension. A link that has utm_source and no utm_medium still creates a session, then Session medium shows (not set). Write all three required fields on every tagged URL, including Shopify Messaging sends and Campaigns shareable links, so neither GA4 nor Shopify has an empty campaign cell to hide traffic in.

Open the live tagged URL, or scan the QR, and confirm the landing address still holds utm_source, utm_medium, and utm_campaign after every redirect. Walk one product to checkout and place a test order. In Shopify, open the order conversion details and choose View full sessions. In GA4, use Realtime or DebugView on the landing page_view, then wait for Traffic acquisition to show Session source / medium and Session campaign after processing.

Use utm_content when source, medium, and campaign stay fixed and you need to compare two creatives or two placements. Typical values are hero_video_v1 versus carousel_v2, or top_button versus footer_link in one email. Shopify Campaigns auto-match rules can ignore extra parameters once source and campaign match, so keep content as an optional column on the sheet rather than a required field for every link.

Related Articles