UTM Tracking for QR Codes: A Convention That Holds Up in GA4 — featured illustration
Analytics

UTM Tracking for QR Codes: A Convention That Holds Up in GA4

5 min read
Create a QR code

Your QR dashboard says the poster got 400 scans this month. Google Analytics says nobody came from it. Both are telling the truth: a scanned QR code opens the browser with no referrer, so GA4 files every one of those visits under Direct, and your best-performing channel looks like nothing at all.

Why QR traffic hides in Direct

When a phone camera opens a URL, it passes no referrer header. There is no previous page, no ad click ID, nothing for GA4 to attribute, so the session lands in Direct next to bookmarks and typed addresses. The traffic is not missing; it is unlabeled.

UTM parameters are the label. They are plain query parameters (utm_source, utm_medium, utm_campaign, utm_content) appended to the destination URL. GA4 reads them on arrival and stores them against the session. Nothing on your site changes; the URL inside the QR code just gets longer.

A convention that scales past one campaign

The common failure is not skipping UTMs, it is improvising them. If the spring poster says utm_source=qr and the summer one says utm_source=QR-poster, GA4 treats them as two unrelated sources and every report needs manual cleanup forever. Decide the rules once and write them down:

ParameterRuleExamples
utm_sourceAlways qr, never anything elseqr
utm_mediumThe surface the code is printed onprint, packaging, poster, receipt
utm_campaignThe initiative, dated if it repeatsspring-menu-2026
utm_contentThe exact physical placementwindow, counter, flyer-a

Two small details carry most of the weight. Keep everything lowercase, because GA4 is case sensitive and qr and QR become two separate rows. Use hyphens instead of spaces, because spaces turn into %20 and make every report miserable to read.

utm_content is the parameter that pays rent. utm_source=qr confirms QR codes send traffic. utm_content=window against utm_content=counter tells you the window placement out-pulls the counter 3 to 1, which is the kind of finding that changes where you print next month.

Keep a plain spreadsheet alongside the convention: one row per printed code with its campaign, medium, content value, final URL, and physical location. Six months from now, when someone asks what flyer-a was, the sheet answers in seconds.

Build the URL first, then the code

The order of operations matters. Write the tagged URL, open it in a browser, confirm the page loads with the parameters still visible in the address bar, then generate the code from that exact string. A code generated from the untagged URL cannot be fixed after printing.

With a dynamic code, the tagging moves one level down and gets safer. The printed code contains a short redirect URL; your full tagged URL sits in the destination field. The scan hits the short link, the redirect delivers the browser to the tagged URL, and GA4 receives every parameter. QRolling's dynamic QR code generator works this way, which also means a typo in utm_campaign is a 30-second dashboard edit instead of a reprint across 5,000 boxes.

Reading the results in GA4

Open Reports, then Acquisition, then Traffic acquisition. The default view groups traffic by channel; switch the primary dimension to Session source / medium and your rows appear as qr / print, qr / packaging, qr / receipt.

For campaign level, add Session campaign as a secondary dimension or filter by it. For placement level, the secondary dimension is called Session manual ad content, which is where utm_content lands. The name is unintuitive enough that many people conclude their tags are broken while the data sits one dropdown away.

Give new tags 24 to 48 hours before judging them: GA4 processing lags, and low-volume rows can be affected by data thresholds. For which of these numbers deserve your attention once the rows appear, the analytics deep dive walks through the metrics one by one.

Three quiet ways the data corrupts

Redirect chains can drop parameters. Every hop between the scanned URL and the landing page is a chance for the query string to vanish, and some shorteners and misconfigured server redirects do exactly that. Scan the final printed code, watch the address bar, and confirm the parameters survived the trip. How redirects should behave under the hood is covered in 301 vs 302 redirects.

A second shortener strips your work. A tagged URL wrapped in a generic shortener whose settings discard query strings fails silently: scans arrive, Direct grows, and nothing looks broken. Keep one redirect layer, owned by you, tested end to end.

The tagged URL leaks into other channels. You tag the landing page for the QR campaign, then a colleague pastes that same URL into the newsletter because it was handy. Now email clicks report as qr / print, and both channels are wrong in opposite directions. The rule: a tagged URL lives in exactly one place, inside the code it was written for. The newsletter gets its own tags or the clean URL.

When you do not need GA4 at all

Match the tool to the question. How many scans, at what times of day, on which device types, from which cities: the scan analytics built into a dynamic QR platform answer all of that with zero tagging and no GA4 setup, because the redirect itself records the event before your site ever loads.

GA4 earns its complexity when the question starts after the landing. Did scanners buy anything? Which channel, QR or email or search, produced signups at the lowest cost? Those questions need UTMs, because only your site analytics can see past the first pageview and stitch the scan to an outcome.

In practice you run both: platform analytics for the scan side, GA4 for the outcome side, with the UTM convention as the thread connecting a poster on a wall to a line in a revenue report.

Do the five-minute audit today: open Traffic acquisition in GA4, set the primary dimension to Session source / medium, and look for qr. If it is not there and your codes are already in the wild, rebuild the busiest one with a tagged destination before the next print order goes out.

Share this article