Track QR code scans in Google Analytics
Your campaign is on ten thousand flyers and Google Analytics says the traffic is Direct. It is not lying; it has nothing else to say. This page is the one fact that explains it, where the tags actually have to go, and why the number on the flyer's code and the number in Google will never agree.
Why a scan is Direct
Google attributes a session from two things: the referrer the browser sends, and any UTM parameters in the address that was opened. A scan has neither by default. Nobody clicked a link on a web page, so there is no referrer; the camera simply opened an address. And if the code goes through a redirect, as nearly every printed code does, the redirect does not add one · ours sends no referrer at all, on purpose, so that the destination learns nothing about the short address a visitor came through.
With no referrer and no tags, Direct is the only drawer Google has. Every scan of every code in every campaign lands in it, indistinguishable from someone typing your URL.
The tags go in the destination, not the code
The only signal that survives the trip is a UTM tag inside the address the phone finally lands on. So the tagged address is the destination page, and the question is only how that address gets into the code:
- Static code · you encode the tagged URL itself. It works, and it is permanent in both senses: the code needs no service to keep working, and the tags it was printed with are the tags it has forever. A longer address also means a denser symbol, which is worth knowing before a small print.
- Dynamic code · you save the tagged URL as the destination behind a short address, and the code encodes only the short address. The tags are in a record you can edit, so a campaign can be renamed, a source corrected or a whole new tagging scheme adopted after the flyers are in the world.
A convention that survives contact with a spreadsheet: one value of utm_medium for the physical channel (print, packaging, menu, signage), utm_source for the
object (flyer, table tent, box insert), utm_campaign for the campaign, and utm_content for the placement when the same object is printed in several. Decide
it before the first code, because a static code cannot adopt it later.
Tags on the short link are a different tool
There is a second place a tag can go, and it does a different job. A tag on the scanned
address itself · tap2u.link/abc?utm_source=flyer · is read by the redirect as a
routing signal and recorded in the code's own scan analytics, so one printed code in two
channels can open two pages and report as two lines. That is source routing, and it runs before the redirect.
What it does not do is reach Google. On an ordinary dynamic link the scanner is sent to the destination you stored, unchanged; the tag on the short address is not appended to it. So the rule is simple. For Google, tag the destination. For per-object splits in the scan analytics, or for routing on the object, tag the short address. Both at once is fine, and a password gate carries the short-address tags across its form so a gated campaign still reports.
Why the two numbers never match
Once the tags are in place, Google reports sessions from your QR source and the code reports scans, and the second number is larger. They count different events:
- A scan is counted at the redirect, before any page loads. No cookie is set, no script has to run, and nothing depends on the destination page finishing. Bot traffic is flagged and shown separately rather than silently removed.
- A session is counted when Google's tag has loaded on the destination page and, in many regions, when the visitor has consented to it. A slow connection that gave up, a browser that blocks the tag, and a declined consent banner are all scans that never became sessions.
Neither number is wrong. The scan count tells you how many people the print reached; the session count tells you how many of them Google was allowed to watch on the page. If the gap is large, it is telling you something about the page, not about the code. What the scan side measures, and what it deliberately does not, is in analytics.
Hosted pages
A code can also land on a page hosted with the code rather than on a site of yours. That page is rendered at our edge and carries no third-party tag, so Google never sees it. Its visits are measured first-party instead, with no cookie on the visitor, which you switch on for 200 credits, once. If the campaign has to appear in Google, point the code at a page you host and tag that address.
Where taproute comes into this
The reason to run a tagged campaign on a dynamic code is the edit. Retagging a destination after printing is a save, not a reprint, and there is no allowance on how often you change it · the code is 1 credit to create, once, and 1 credit per scan on prepaid credits, with no subscription. The ecommerce page shows the shape this usually takes, an insert printed once and pointed at whichever page the campaign is on this month.
The failure mode, stated before you print: a code on a wallet that has run out of credits serves a paused notice instead of the destination, after a grace period of 14 days or 5 percent of the last top-up in scans, whichever ends first. Those scans are counted on our side and never reach Google, which is one more reason the two numbers differ. Topping up restores the code without touching the print.
Questions
Why do my QR code scans show as Direct in Google Analytics?
Because a scan has no referrer. Nobody clicked a link on a web page; the camera opened an address. A redirect in between does not add one either · ours deliberately sends none. With nothing to attribute, Google files the session under Direct. The only signal that survives the trip is a UTM tag inside the address the phone finally lands on.
How do I add UTM parameters to a QR code?
Put them on the destination URL, the page the scan should land on, not on the code. For a static code that means encoding the tagged URL, and the tags are then in the ink. For a dynamic code it means saving the tagged URL as the destination, which you can edit after printing.
Can I change the UTM tags after the code is printed?
Only on a dynamic code. Its destination is a record you edit, so retagging a campaign, renaming a source or fixing a typo is a save, and the printed pattern never changes. A static code encodes the tagged URL itself, so the tags it was printed with are the tags it has.
Why does the scan count differ from the Google Analytics sessions?
They count different events. A scan count is taken at the redirect, before any page loads, with no cookie and no script. Google counts a session once its tag has loaded on the destination page and, in many regions, once the visitor has consented. Slow connections, blocked scripts and declined consent all fall between the two. Both are right about what they measure.
Do you pass UTM tags from the scanned link through to my destination?
Not on an ordinary dynamic link. A tag on the short address is read as a routing signal and recorded in your scan analytics, and the redirect sends the scanner to the destination you stored, unchanged. If Google needs to see a tag, the tag belongs in that stored destination.
Can Google Analytics run on a hosted page?
No. A hosted page is rendered at our edge and carries no third-party tag. Its visits are measured first-party instead, with no cookie set on the visitor, which you switch on for 200 credits, once. If Google has to see the traffic, point the code at a page you host and tag that address.