UTM Parameters for QR Codes: A Naming Convention You Can Copy
One opinionated UTM naming convention for QR codes, built around the physical channel and placement, with copy-paste worked examples.
Most QR-and-UTM advice offers you a menu of options and leaves the decision to you. Here's one convention instead, opinionated on purpose: utm_source=qr on every code, utm_medium set to the physical channel the code lives on, utm_campaign naming the campaign, and utm_content identifying the specific physical placement. Copy it as written, adjust the vocabulary to match your own reporting, and every QR code you print from this point forward will roll up into the same reporting structure without a naming argument six months from now.
The four parameters, and what each one is for
| Parameter | What it should carry | Example value | Why |
|---|---|---|---|
utm_source |
The channel family: always qr for a scanned code |
qr |
Distinguishes scan traffic from a typed URL or a clicked link, even when the destination is identical |
utm_medium |
The physical channel the code sits on | print, packaging, ooh, event, direct-mail |
This is the dimension most QR campaigns get wrong by putting qr here instead |
utm_campaign |
The campaign name, shared across every placement in that campaign | festive-sale |
Groups every placement's traffic under one campaign for reporting |
utm_content |
The specific physical placement | shelf-talker-aisle3, receipt-footer, booth-standee |
The only parameter that tells you which physical spot earned the scan |
Four parameters cover nearly every QR campaign. A fifth, utm_term, exists for paid-keyword testing and rarely has a sensible value on a printed code; leave it out rather than filling it with something that doesn't mean anything.
Why utm_medium=qr is the mistake almost everyone makes
It feels natural to put the channel's own name in utm_medium, and most QR generators that suggest a default value nudge marketers toward exactly that. The problem is what it costs: utm_medium is the field most analytics reports group by when comparing channels, so setting it to qr on every single code merges packaging, print advertising, out-of-home, and event placements into one undifferentiated bucket labelled "qr". You can no longer ask which physical channel is actually driving results, which is usually the entire reason a marketer wanted QR analytics in the first place.
The fix is the reallocation this convention makes deliberately: utm_source=qr answers "was this a scan," once, in one field, and utm_medium is freed up to answer "what physical channel was this scan on," which is the question that actually varies from placement to placement and actually needs comparing.
The case-sensitivity trap
UTM values are case-sensitive in every major analytics platform, Google Analytics included: utm_source=google and utm_source=Google are recorded as distinct values, not normalised into one. Apply that same rule to your own QR convention and the risk is identical. A batch of codes tagged print and a later batch tagged Print, made by two people or six months apart, will not merge in a report. They'll sit as two separate rows, quietly splitting one channel's numbers in half and making both halves look smaller than the channel actually performed.
The fix costs nothing and needs saying exactly once: pick all-lowercase, hyphen-separated values as a house rule (direct-mail, not Direct Mail or directMail), write the rule down somewhere the whole team can see it, and hold every code, from the first one to the five-hundredth, to it. Catching a mismatched value after a hundred codes are already printed and live means fixing it in the analytics platform's configuration, not in the print run, which is a far worse place to discover the problem.
How the parameters survive a dynamic redirect
A dynamic QR code's power here is straightforward and worth stating precisely: the UTM parameters are built into the destination URL at the point the code is created or edited, and a scan simply carries that full destination URL, query string and all, through the redirect to the landing page. Whatever analytics tool is running on that landing page sees the same UTM values a marketer would see if they'd typed or clicked the exact same URL themselves. The redirect isn't adding intelligence here; it's passing through what was already configured.
What follows from that is a real advantage for dynamic codes specifically: if a campaign name changes mid-run, or a placement gets renamed, or you realise utm_content needs a different value, editing a dynamic code's destination after it has already been printed lets you correct the tagging going forward without touching the printed artwork at all. A static code's UTM values, by contrast, are baked into the pattern permanently the moment it's printed, and a tagging mistake on a static code is a tagging mistake for the life of that print run.
Why the placement dimension is what makes offline creative comparable
The entire reason to bother tagging a printed QR code at all, rather than just watching the total scan count come in, is comparability. Digital marketing gets this for free: every click on every ad already carries a URL, a placement ID, an ad group. Print, packaging and out-of-home have never had that, which is exactly the gap utm_content closes, provided it's actually populated at the level of the physical placement rather than left at the campaign level.
A campaign running the same offer across a shelf-talker, a receipt footer, and a counter standee, tagged with one shared utm_content value across all three, produces one merged number and answers nothing about which placement earned its spot in next quarter's plan. The same campaign with three distinct utm_content values produces three comparable rows in the same report, using the same campaign name, the same medium, the same source, differing only in the one field designed to vary. That's what turns three pieces of printed material sitting in three different rooms into data a media plan can actually be built on, and it's the same principle behind treating a QR scan as first-party attribution rather than an anonymous number with no origin.
Where this convention fits against the rest of your QR analytics
UTM parameters and a QR platform's own analytics answer different halves of the same question, and it's worth being clear which is which before building a report around either. A dynamic code's per-code analytics tells you how many scans a specific printed code received, when, from roughly where, and on what kind of device: everything the platform can observe about the scan itself. UTM parameters carried through to the landing page tell you what happened after the scan, inside whatever analytics tool runs your website: which page the visitor landed on, whether they converted, how long they stayed. Neither replaces the other, and a report built on only one half will always be missing something the other half would have explained.
This is also why the convention needs to be decided centrally rather than left to whoever creates each code. A campaign spanning packaging, an in-store standee, and a direct-mail piece, run by three different people on three different weeks, will drift toward three different tagging habits unless the four-field convention above is written down and treated as non-negotiable. The cost of drift is invisible until someone tries to build a single report across the whole campaign and discovers that half the placements used one naming pattern and half used another, at which point the fix is manual cleanup in the analytics platform rather than a five-minute rule applied at creation time.
A worked set of tags
A festive retail campaign running across three placements, using this convention throughout:
| Placement | Full parameter set |
|---|---|
| Shelf-talker, aisle 3 | utm_source=qr&utm_medium=packaging&utm_campaign=festive-sale&utm_content=shelf-talker-aisle3 |
| Receipt footer | utm_source=qr&utm_medium=print&utm_campaign=festive-sale&utm_content=receipt-footer |
| Store window, closed hours | utm_source=qr&utm_medium=ooh&utm_campaign=festive-sale&utm_content=window-closed-hours |
Every row shares the campaign name and the source. Only the medium and content values change, and they change for a reason: a different physical channel, a different physical spot. That's the whole convention, applied.
What this means for your next campaign
Write the four-field convention down once, in whatever document your team already uses for campaign briefs, and treat it as fixed rather than reinvented per campaign. Set utm_source=qr on every code without exception. Choose utm_medium from a short, agreed list of physical channels, not from whatever word comes to mind that day. Give utm_content a distinct value per physical placement, always, even when it feels like overkill for a two-placement campaign, because the campaign that actually needs the comparison is never the one you predicted in advance. Keep every value lowercase and hyphenated. None of this requires new tooling; it requires deciding the convention before the first code goes to print rather than after the data already looks like six different campaigns instead of one, tagged inconsistently. Where a campaign is genuinely testing two versions of the same placement against each other, a structured A/B test is the next layer to add on top of this same tagging discipline, not a replacement for it.
Straight answers
What UTM parameters should I use on a QR code destination?
Four are enough for almost every campaign: utm_source=qr to flag the channel family, utm_medium set to the physical channel (print, packaging, ooh, event, or similar), utm_campaign for the campaign name, and utm_content for the specific physical placement. Add utm_term only if you're genuinely testing paid-keyword-style variants, which is rare for a printed code.
Should utm_medium be set to "qr" on a QR code?
No. That's the most common mistake in QR tagging, because it throws away the one piece of information a QR scan uniquely offers: where the code physically was. Set utm_source=qr instead to flag that the visit came through a scan, and use utm_medium for the physical channel, such as print, packaging, ooh, or event, so your reports can compare channels properly.
Are UTM parameters case-sensitive?
Yes, in every major analytics platform, including Google Analytics. "Print" and "print" are recorded as two different values, which silently splits one channel into two rows in a report. Decide on all-lowercase as a house rule before your first code goes to print, and hold every code to it, since fixing this after a hundred codes are already live is far more painful than setting the rule on day one.
Do UTM parameters survive a QR code redirect?
Yes, when the parameters are built into the destination URL at creation time, as they are for a dynamic QR code's configured destination. The redirect carries the full destination URL, query string included, to the landing page, so the analytics tool running there sees the same UTM values a marketer would see on a typed or clicked link. A redirect will not invent UTM values on its own; if they weren't added to the destination first, nothing downstream sees them.
How many UTM values should one QR campaign use?
One value per physical placement, at minimum, using utm_content. A single utm_source/utm_medium/utm_campaign set shared across every placement in a campaign is fine and often correct, since it groups the whole effort together; collapsing utm_content to one shared value across several different physical spots is the mistake, because it's the placement dimension that lets you compare where the campaign actually worked.
-
UTM parameters are case-sensitive; utm_source=google and utm_source=Google are recorded as distinct values
https://support.google.com/analytics/answer/10917952