How to Track QR Code Scans in Google Analytics 4

By • 3 November, 2026 • SEO & Marketing • 11 minutes read

Track QR code scans in GA4 for free with UTM links: which tags to use, why qr traffic shows as Unassigned and how to fix it, with real tested examples.

To track QR code scans in Google Analytics 4, put UTM parameters on the link before you turn it into a code, for example https://www.example.com/menu?utm_source=flyer&utm_medium=qr&utm_campaign=spring_menu_2026. Every scan that opens your page then shows up in GA4 as a session from flyer / qr. Build the link with our free UTM link generator, paste it into the free QR code generator, and download a PNG or SVG. Both tools are free, need no account and run in your browser.

The catch most guides skip: GA4 has no default channel for QR codes, so utm_medium=qr traffic lands in Unassigned until you add a custom channel group. Every example below was run on November 3, 2026: links from our live UTM tool in Chrome, QR codes read back with two decoders, and channels checked against the rules Google publishes for GA4.

How QR code tracking in GA4 actually works

A static QR code is just text, here a URL. When someone scans it, their phone opens that URL like any other link, and your GA4 tag reads the utm_ parameters from the address. GA4 never sees the scan itself. It only sees the page view that follows. Two practical consequences:

  • You're counting visits, not scans. A scan that's never opened, a phone with no signal, or a visitor who blocks analytics won't show up. Treat GA4's numbers as a floor.
  • The landing page needs your GA4 tag. If the code points to a PDF, a Google Maps listing or another company's site, GA4 has nothing to record. Point it at a page on your own site, even one that just links onward.

So you don't need a paid "dynamic QR" service, which counts scans through its own redirect. A static code with UTMs puts the same campaign data in your own analytics and never expires. The trade-off is that its destination is fixed once printed. If you may need to change it, encode a short URL on your own domain that redirects to the tagged link.

Step by step: create a trackable QR code

  1. Choose the landing page. Use the exact final URL, with https:// and the right www or non-www version, so the code doesn't depend on a redirect.
  2. Open the UTM link generator and paste the URL.
  3. Fill in three fields. UTM Source is where the code is printed (flyer, poster, table_tent, packaging). UTM Medium is qr, the same on every code. UTM Campaign is what you're promoting (spring_menu_2026). Use UTM Content to tell versions apart, like table_12 or poster_b.
  4. Click outside the last field. The generator rebuilds the link when a field loses focus, not on every keystroke. In our test, right after we finished typing the campaign, the result still read ...?utm_source=flyer&utm_medium=qr, and the campaign appeared only after a click elsewhere. Check that the result shows all your parameters before you copy it.
  5. Paste the link into the QR code generator (type Text), choose a size and error correction level, and download a PNG for screens or an SVG for print.
  6. Scan your own code with your phone camera, or upload the image to the QR code reader, and confirm that the decoded URL matches the original character for character.
  7. Test in GA4 before you print (see the final section).

Try it now: build your tagged link, then turn it into a QR code. Both pages build the result locally in your browser.

Worked examples (real outputs from our tools)

We typed these inputs into the live UTM link generator. The results are copied exactly as the tool produced them:

InputGenerated link
URL https://www.example.com/menu, source flyer, medium qr, campaign spring_menu_2026https://www.example.com/menu?utm_source=flyer&utm_medium=qr&utm_campaign=spring_menu_2026 (89 characters)
Same, but source Flyer, medium QR, campaign Spring Menu 2026...?utm_source=Flyer&utm_medium=QR&utm_campaign=Spring%20Menu%202026
URL https://www.example.com/menu?lang=en#hours, source table_tent, content table_12https://www.example.com/menu?lang=en&utm_source=table_tent&utm_medium=qr&utm_campaign=spring_menu_2026&utm_content=table_12#hours
URL typed without a scheme: example.com/menuhttps://example.com/menu?utm_source=flyer&... (https added, no www)

Spaces become %20 by default, or + if you pick it under Encode spaces as (both valid, but underscores are cleaner; the length figures below used +). The link updates as you type, and there is a utm_id field for a campaign ID. Existing parameters like lang=en are kept, and the #hours fragment stays at the end, where it must be: UTMs placed after a # never reach GA4. The tool adds https:// but can't guess www, so type the full address. To proofread a long link, paste it into the URL parser. For the third link, it listed all five query values separately, with hours as the fragment.

A QR code grows in "versions": version 1 is 21×21 modules (the small squares), and each version adds 4 modules per side. More characters mean a higher version and smaller squares at the same printed size. We generated each link at 512×512 px and read the version back with the zxing-cpp decoder:

Encoded URLCharactersVersion at MVersion at H
https://www.example.com/menu (no UTMs)283 (29×29)4 (33×33)
https://www.example.com/m?utm_source=flyer&utm_medium=qr&utm_campaign=sp26745 (37×37)8 (49×49)
Flyer link from the table above896 (41×41)9 (53×53)
Table-tent link with lang and #hours1298 (49×49)11 (61×61)
Long path plus long values (poster_downtown_bus_stop, poster_a3_version_b)18910 (57×57)14 (73×73)

On a 25 mm code, version 5 gives modules about 0.68 mm wide, while version 10 shrinks them to about 0.44 mm. That makes a real difference for cheap printing, glossy surfaces and scanning from a distance. Every one of these codes decoded perfectly with zxing-cpp and with our QR code reader, including the & separators and the #hours fragment, so length isn't a correctness problem. It's a print-quality problem. Keep values short (sp26 instead of spring_menu_launch_2026), skip utm_term (it's for paid keywords), and use error correction M unless you're placing a logo over the code.

The GA4 trap: utm_medium=qr shows up as Unassigned

GA4 sorts every session into a default channel (Organic Search, Email, Referral and so on) using fixed rules that you can't edit. We checked our sample tags against the rules in Google's Default channel group help page and its downloadable list of sources:

source / medium / campaignDefault channelWhy
flyer / qr / spring_menu_2026UnassignedNo rule mentions qr, and flyer isn't a known source
flyer / print or offlineUnassignedNeither value has a rule either
instagram / qrOrganic Socialinstagram is on Google's social source list
flyer / qr / coffee-shop-flyerOrganic ShoppingCampaign names matching -shop or shopping count as shopping
flyer / mobile-qrMobile Push NotificationsAny medium containing mobile
flyer / qr-videoOrganic VideoAny medium containing video
flyer / qr_cpmPaid OtherAny medium containing cp

So don't try to dodge Unassigned with clever medium names. They just move your scans into the wrong channel. Keep utm_medium=qr and give it a channel of its own:

  1. In GA4, go to Admin → Data display → Channel groups and click Create new channel group. You start from a copy of the default group. You need Editor access or higher.
  2. Click Add new channel, name it QR codes, and add the condition Medium exactly matches qr.
  3. Click Reorder and drag QR codes to the top, because traffic goes to the first channel it matches. Otherwise instagram / qr would still fall into Organic Social.
  4. Save the group, then pick it as the primary dimension in Reports → Acquisition → Traffic acquisition.

Per Google's documentation, custom channel groups apply to your data retroactively, and standard properties can have 2 of them with up to 50 channels each. Channel conditions aren't case sensitive, but the values in your reports are: Google states that utm_source=google and utm_source=Google are different values, so Flyer / QR and flyer / qr would show up as two rows. Use lowercase everywhere.

Redirects and shorteners: make sure the UTMs survive

If the code points to a URL that redirects, the redirect must carry the query string along. Most do: our URL redirect checker showed https://google.com/?utm_source=flyer... answering 301 to https://www.google.com/?utm_source=flyer... with every tag intact. But in a curl test, https://fb.com/?utm_source=flyer&utm_medium=qr answered 301 to plain https://www.facebook.com/, with the tags gone. A redirect like that on your site turns every scan into Direct traffic. Check the last URL in the chain, not the first; see how to check if a redirect is 301 or 302.

Common mistakes

  • One code for every placement. If the flyer and the poster share a code, you can't compare them. Change utm_source or utm_content for each placement. It costs nothing with static codes.
  • Using UTMs on your own website's internal links. QR codes are entry points, so tag them. Don't tag links between your own pages; our UTM parameters guide for GA4 explains why.
  • Low-contrast colors. A brand-colored code that's too pale may not scan. Our generator warns about low contrast. Dark on light is safest.
  • Hiding the destination. Phones preview the URL before opening it. Your own domain looks more trustworthy than a random shortener; see how to check if a QR code is safe.

Test it in GA4 before you print

Open a private browser window, which counts as a new user, and visit your tagged link (or scan the code with a phone that hasn't visited your site). In GA4, open Reports → Realtime and switch the Users by First user source card to First user campaign. Google notes that Realtime shows user-scoped, first-acquisition dimensions, which is why a fresh browser matters. If the campaign appears within a few minutes, the tag, the link and any redirects all work. The full numbers appear in Traffic acquisition later, under Session source / medium and Session campaign.

Frequently asked questions

Can Google Analytics track QR code scans?

Indirectly. GA4 can't see the scan itself, but if the QR code contains a link with UTM parameters, every scan that opens your page is recorded as a session with that source, medium and campaign.

What UTM medium should I use for QR codes?

Use qr on every code and put the placement in utm_source, like flyer or poster. GA4 has no default QR channel, so add a custom channel group with Medium exactly matches qr, placed first.

Why does my QR code traffic show as Unassigned in GA4?

Because no default channel rule matches the medium qr (or print, or offline). Create a custom channel group called QR codes. It applies to past data too.

Do I need a dynamic QR code to track scans?

No. A static code with UTM parameters gives you scan visits in your own GA4 for free, with no expiry. A dynamic code only adds the ability to change the destination after printing, and a redirect on your own domain can do that too.

Will UTM parameters make my QR code harder to scan?

They make it denser. In our tests, a 28-character URL produced a version 3 code, and the 89-character tagged version produced version 6, both at error correction M. Short values and medium error correction keep it easy to scan.

Are the UTM and QR code generators free?

Yes. Both are free, need no account and run in your browser. There's no watermark, and the codes don't expire because they're static.

Ready to measure your print campaign? Tag your link with the UTM link generator, turn it into a code with the QR code generator, and double-check it with the QR code reader before it goes to the printer. For printed Wi-Fi codes, see how to create a Wi-Fi QR code.

How to Check If a Page Is Noindex (Meta Tag and Header)

2 November, 2026

Check if a page is noindex in seconds: the robots meta tag, the hidden X-Robots-Tag header and robots.txt traps, with real checks and free t..

How to Extract All URLs From a Sitemap (Free, No Code)

1 November, 2026

Pull every URL out of an XML sitemap in seconds, no code. Real tests on index files, ampersands, namespaces and duplicates, with fixes.

How to Download a YouTube Thumbnail in HD (Free)

31 October, 2026

Save any YouTube thumbnail in every size up to 1280x720. Real tests, why HD is sometimes a grey box, how to handle Shorts links, and fair re..