Free tier, no card requiredDynamic QR codes that update after printGDPR-compliant scan analyticsBuilt for agencies, freelancers & in-house teamsFree tier, no card requiredDynamic QR codes that update after printGDPR-compliant scan analyticsBuilt for agencies, freelancers & in-house teamsFree tier, no card requiredDynamic QR codes that update after printGDPR-compliant scan analyticsBuilt for agencies, freelancers & in-house teamsFree tier, no card requiredDynamic QR codes that update after printGDPR-compliant scan analyticsBuilt for agencies, freelancers & in-house teams
All posts
Two QR codes side by side: a small compact code and a larger, denser code connected by a tag icon, with three colour-coded labelled tag chips next to the denser code.
Guide

QR code UTM parameters: a naming convention that scales across every client

Why a scanned QR code shows up as Direct in GA4, a UTM naming convention built for agencies running many clients, and the QR-specific trade-off nobody mentions: tagged URLs make your code denser and harder to scan.

ScanKit

ScanKit · Organization

· 16 min read

Print a hundred flyers across ten clients, drop a QR code on each one, and after launch week your GA4 reports show the same thing for almost all of them: a spike in Direct traffic. No source, no medium, no campaign. Just a pile of unattributed sessions that could be the QR code, could be someone typing the URL from memory, could be anything. The scan happened. The attribution did not.

The fix is UTM parameters, and most explanations of them stop at "add some tags to your URL." That is fine advice for one marketer running one campaign. It falls apart the moment an agency is running this across a dozen clients at once, because the failure mode is not "we forgot to tag the link." It is "everyone tagged their links slightly differently," which is quietly worse: the reports look complete, but Facebook, facebook and Instore-QR are three different rows in three different clients' dashboards, and nobody notices until a quarterly report has to explain the gap.

This post covers what UTM parameters actually do, why a scanned QR code defaults to Direct without them, a naming convention built to survive multiple clients rather than one campaign, and a QR-specific problem almost nobody writes about: a UTM string makes your URL longer, and a longer URL makes your QR code denser. Past a certain point, that trade-off starts working against you in exactly the print conditions agencies rely on: small flyers, laminated table tents, low-quality newsprint.

What UTM parameters actually are

UTM parameters are five specific query-string fields appended to a URL that tell an analytics platform where a visit came from. Google's own documentation is explicit that only three are required in practice: utm_source (where the traffic originates, e.g. flyer or google), utm_medium (the marketing channel, e.g. qr or email), and utm_campaign (the specific initiative, e.g. spring-menu-launch). Two more are optional and situational: utm_term, mostly used for paid search keywords, and utm_content, used to distinguish between variants, such as two QR placements on the same poster.

Leave a required field blank and GA4 does not guess. It reports the value as (not set), which is functionally the same problem as no tag at all: a session you can see but cannot explain.

One detail that causes more damage than its size suggests: UTM values are case-sensitive. Google's own help documentation states this plainly and recommends lowercase as standard practice. utm_source=Instagram and utm_source=instagram are not the same value to GA4. They become two separate rows in every report, splitting a single channel's traffic in half for no reason other than someone typed a capital letter. This is not a bug you can configure away. It is how the platform is built, and the only real defence is a naming convention enforced before links go live, not cleaned up after.

There is no official maximum length for a UTM value, but there is a practical one worth knowing: GA4 caps most event parameter values at 100 characters, so an overly descriptive utm_campaign string can get silently truncated in reporting. Keep values short and structured rather than descriptive sentences.

Why a scanned QR code shows up as Direct

A QR code does not open a link the way a browser click does. There is no referring page, so there is no HTTP referrer header for GA4 to read. Google's documentation on Direct traffic is specific about the mechanism: a session is classified as (direct) / (none) when GA4 finds no UTM parameters, no recognised advertising click ID, and no referrer it can match to a known source. A typed URL, a link from a PDF, and a scanned QR code all land in exactly the same bucket for exactly the same reason: nothing in the request tells GA4 where the visitor came from.

That is the whole story. It is not a QR-specific bug, and it is not something a QR platform can fix on your behalf, because the missing information (source, medium, campaign) was never encoded in the request to begin with. The fix has to happen at the URL level, before the code is generated. For the full walkthrough of setting this up correctly in GA4, see tracking QR code scans in Google Analytics 4.

Worth flagging separately, because it catches experienced teams too: a redirect that strips query parameters along the way (an https-to-http redirect, or a URL shortener that doesn't pass them through) will drop your UTM tags even if you built the link correctly. If a client's Direct traffic looks unexplainably high, check the full redirect chain the scan actually travels through, not just the URL printed on the QR code.

A naming convention that survives more than one client

Most UTM advice assumes one person managing one set of campaigns, so "just be consistent" is enough. An agency needs something closer to a schema: fixed rules a junior team member can follow correctly on their first day, without a decision to get wrong.

A structure that holds up at agency scale:

  • utm_source, the physical or digital placement, not the client. Use flyer, poster, business-card, menu, email-signature, packaging. This is the single most useful field for answering "which placement actually drives scans," and it is the one field most naming conventions leave too vague to be useful.
  • utm_medium, fixed to qr for every single QR-originated link, across every client, with no exceptions. This is what lets you filter "all QR performance" across your entire agency in one report, rather than reconstructing it client by client.
  • utm_campaign, a structured pattern, not free text. Something like client-campaign-yyyymm, e.g. northside-cafe-summer-menu-202607. The date suffix matters more than it looks: it stops a recurring seasonal campaign from silently overwriting last year's data under the identical campaign name.
  • utm_content, reserved for genuine variants of the same placement, most often A/B tests. Two QR codes on the same poster testing "Scan for 10% off" against "Scan to see the menu" get identical source, medium and campaign, differing only in content, such as content=offer-a versus content=offer-b. That is what makes the A/B split visible in a single report rather than two separate ones you have to manually reconcile. See how to A/B test a QR code campaign for the full testing setup this feeds into.

The rule that actually enforces this, more than any naming pattern, is governance: one shared, visible source of truth for every tagged link across every client, and one enforced case convention (lowercase, always) rather than trusting memory. If your agency already organises codes into a workspace per client, that structure is a natural place to also standardise the taxonomy, since the same boundary that separates client data should separate their utm_campaign values too. See one workspace per client for how that separation works in practice.

The QR-specific problem: UTM length versus scan reliability

Here is the part almost no UTM guide mentions, because almost no UTM guide is written by anyone who also has to print the resulting code.

A QR code can encode text in a few different modes, and the mode matters because each one packs data at a different density. The most efficient is numeric mode, then alphanumeric mode, which supports a 45-character set: digits, uppercase letters, space, and a handful of symbols ($ % * + - . / :). A tagged URL cannot use alphanumeric mode. It contains lowercase letters, plus ?, &, =, and _, all of which sit outside that 45-character set. That forces the encoder into byte mode, which is meaningfully less space-efficient per character than alphanumeric mode. In other words: the moment you add UTM parameters, you have already made your QR code denser than the bare domain would have needed, before you have added a single character of tracking data.

From there, more characters means a higher QR version, and a higher version means a denser grid of modules squeezed into the same printed size. The capacity table (byte mode, which is what a UTM URL uses) makes the jump concrete:

  • Version 1 (21x21 modules): 17 characters at error correction L, down to 7 at H.
  • Version 3 (29x29 modules): 53 characters at L, down to 24 at H.
  • Version 5 (37x37 modules): 106 characters at L, down to 44 at H.
  • Version 7 (45x45 modules): 154 characters at L, down to 64 at H.
  • Version 10 (57x57 modules): 271 characters at L, down to 119 at H.

A bare short domain fits comfortably in Version 1 or 2. A realistic UTM-tagged URL, with source, medium, campaign and a date suffix, typically runs somewhere around 90 to 110 characters once the domain is included, which lands you around Version 7 or 8 at a medium error correction level. That is visibly more modules packed into the same physical square, which means smaller individual modules if the printed size stays the same, which means less tolerance for a cheap printer, a slightly soft focus, or a laminate glare.

Error correction adds a second, related trade-off. Denso Wave's own figures put recoverable data at roughly 7% for level L, 15% for M, 25% for Q and 30% for H. Higher levels survive more print damage and off-angle scanning, but at a fixed version they hold less data, and at a fixed character count they push you to a higher, denser version instead. There is no setting that gives you both maximum recovery and maximum capacity in a small code; you are always trading one against the other. For the fuller breakdown of when to use each level, see QR code error correction: what L, M, Q and H actually mean.

The practical fix, and the reason this problem is more manageable than it first looks, is that you do not have to encode the full tagged URL in the printed QR code at all. A dynamic QR code encodes a short redirect URL, one that stays at Version 1 or 2 regardless of how elaborate the destination's UTM string gets, and the redirect itself carries the visitor through to the fully tagged destination server-side. The QR code stays small and forgiving to print; the analytics stay fully tagged. This is one of the clearer practical arguments for dynamic over static QR codes specifically for agencies running UTM-heavy campaigns, alongside the more commonly cited one of being able to fix a link after printing. For the wider comparison, see dynamic vs static QR codes.

A practical sequence that keeps both the tracking and the print quality intact:

  1. Build the fully tagged destination URL first, using your agreed naming convention. Google's own Campaign URL Builder is the canonical tool for this and avoids typos in parameter names, which matter: utm_medium misspelled as utm_meduim is invisible to GA4 and simply does not attribute.
  2. Point a dynamic QR code at that tagged URL rather than encoding the tagged URL directly. The printed code then only needs to hold a short redirect, keeping it at a low version regardless of how long the destination URL is.
  3. Choose error correction based on the print environment, not by default. A code that will sit somewhere clean and well-lit, like a countertop table tent, can safely use L or M. A code going on an outdoor poster, a shipping label, or anywhere it might pick up dirt or damage, is worth the capacity cost of Q or H.
  4. Test the actual printed size before the full run. Scan it from a normal phone distance, in the lighting the final location will actually have, not a monitor.

Common mistakes that quietly break attribution

A handful of specific failure patterns come up often enough to name directly, because each one looks like a working setup right up until someone tries to reconcile the numbers.

Case inconsistency is the most common and the easiest to prevent. Flyer, flyer and FLYER are three different values to GA4, not one. The only real fix is enforcing lowercase before a link goes live, not after a report looks wrong.

Tagging internal links is a separate, less obvious mistake with the same root cause: adding UTM parameters to a link between two pages on your own site overwrites the visitor's original session source with "your own site" as the referrer, misattributing conversions to an internal channel that did not actually bring anyone in. UTM parameters belong on links leaving a channel you do not control (a printed flyer, an email, a third-party site), never on internal navigation.

Redirect chains that drop query parameters silently erase UTM data partway through the journey, which is why the QR code, the redirect, and the final landing page all need checking together, not just the code itself.

And the costliest mistake of all is printing before testing: five thousand flyers with an untagged, mistyped, or dead-linked QR code is not a reporting problem, it is a reprint bill. A dynamic QR code at least contains that mistake, since the destination can still be corrected after the print run has already gone out; see changing a QR code's destination without reprinting for how that recovery works if it happens to you.

Once the tagging is consistent, the data it produces is only useful if you know what to do with it. See QR code analytics: which scan metrics matter for turning tagged scan data into something a client report can actually use, and how to calculate QR code campaign ROI for connecting that attribution through to a number a client cares about.

Frequently asked questions

What is a UTM QR code?

It is a standard QR code that encodes a URL carrying UTM parameters (source, medium, campaign, and optionally term and content) in its query string, so that when someone scans it and lands on the destination, an analytics platform like GA4 can attribute the resulting session to that specific placement rather than logging it as unattributed Direct traffic.

Why does GA4 show QR code scans as Direct traffic?

Because a scanned QR code has no HTTP referrer, the same as a typed URL. Without UTM parameters in the destination link, GA4 has nothing to attribute the session to, so it defaults to the (direct) / (none) classification, regardless of how the visitor actually arrived.

What are the five UTM parameters?

utm_source, utm_medium and utm_campaign are the three Google recommends using on essentially every tagged link. utm_term and utm_content are optional, used respectively for paid search keywords and for distinguishing between variants of the same link, such as an A/B test.

Should utm_medium be "qr", "qr-code" or "print"?

Pick one exact value and use it for every QR-originated link across every client, with no exceptions. Most agencies standardise on qr, since it is unambiguous and lets you filter "all QR performance" in one query. print is too broad, since it would also catch non-QR print channels and merge data that should stay separate.

Are UTM parameters case-sensitive in GA4?

Yes. This is documented directly by Google, not an assumption. utm_source=Google and utm_source=google are treated as two different values and will appear as separate rows in reports. Lowercase, enforced consistently, is the only real defence.

Does adding UTM parameters make a QR code harder to scan?

It makes the code denser, which is not quite the same thing but leads to the same practical risk. UTM URLs require byte mode encoding rather than the more compact alphanumeric mode, and the added characters push the code to a higher version with a denser module grid. At a fixed print size, that means smaller individual modules and less tolerance for print quality issues. The fix is not avoiding UTM tags; it is pointing the QR code at a short dynamic redirect instead of the full tagged URL.

Can you add UTM parameters to a static QR code?

Yes, technically. The parameters live in the destination URL, not in anything specific to dynamic codes. The practical drawback is that a static code with a long tagged URL baked directly into it is both denser to scan and permanently fixed. If the campaign naming convention changes, or the link needs correcting, the printed code itself has to be reprinted.

What happens if you print QR codes without UTM tags first?

Every scan lands in GA4 as Direct traffic, indistinguishable from someone who typed the URL from memory. With a static QR code this data gap cannot be closed retroactively once it has been printed. With a dynamic QR code, the fix is to update the destination URL to include the tags; scans from that point forward attribute correctly, though the untagged period remains unattributed.

How do agencies avoid UTM naming collisions across multiple clients?

By treating the naming convention as a fixed schema rather than a guideline: a controlled, short list of allowed utm_medium values, a structured pattern for utm_campaign (client, campaign, date), enforced lowercase, and one shared source of truth listing every tagged link currently in use, so nobody is guessing at what the last person named a similar campaign.

The short version

UTM parameters are the only thing that stops a scanned QR code from disappearing into GA4's Direct traffic bucket, because a scan carries no referrer of its own. The three that matter are source, medium and campaign; keep them lowercase, keep the pattern structured rather than descriptive, and fix utm_medium to a single value for every QR link across every client. Separately, remember that a tagged URL is longer and denser to encode than a bare domain, so point your QR codes at a short dynamic redirect rather than baking the full tagged link directly into the print. Build the naming convention once, write it down somewhere every client's account has to use, and the reporting gap that currently shows up as unexplained Direct traffic turns into a channel you can actually defend in front of a client.

Share

Keep reading