How to Track QR Code Scans Without an App or a Subscription
A printed QR code cannot count its own scans. All tracking happens at the destination URL, so the free way to measure scans is to tag that URL with UTM parameters and read the results in Google Analytics 4, or to route every scan through a short redirect link on your own domain and count the hits in your server log.
This guide covers both free methods step by step, plus per-location codes so you know exactly which poster earned each scan, what paid dynamic QR services actually add for their monthly fee, and a short privacy note. Setup time for the UTM method is about 15 minutes if you already run GA4 on your site.
The honest truth: a printed code reports nothing
ISO/IEC 18004, the standard behind QR, defines how characters become a grid of black and white modules, how that grid carries error correction, and how a reader decodes it. Not one clause covers networking. A static code that encodes https://example.com/sale stores exactly those characters, so there is no beacon, no callback, no hidden counter in the pattern. The phone decodes the grid locally, and the scanner app reports nothing back to you.
Every scan count you have ever seen in a QR dashboard was measured at a server after the phone opened the link. That means all tracking is destination tracking, and it also means you can build the same measurement yourself for free. There are three ways to do it, ranked below from zero cost upward.
Method 1: UTM parameters plus GA4
UTM parameters are short tags added to the end of a URL. Your page ignores them, but GA4 reads them and files each visit under the source, medium, and campaign you chose. How to track QR code scans with UTM comes down to five steps.
- Start with the exact destination URL, for example https://example.com/spring-sale.
- Append a question mark, then your tags joined by ampersands.
- Worked example: https://example.com/spring-sale?utm_source=qr&utm_medium=print&utm_campaign=spring25
- Generate the QR code from the full tagged URL, never the bare one.
- Scan it once yourself, then open GA4 under Reports, Acquisition, Traffic acquisition, and set the dimension to Session source / medium. Your test appears in the Realtime report within about 30 seconds, while standard reports can take 24 to 48 hours to settle.
Keep every value lowercase. GA4 is case sensitive, so print and Print land in two separate rows and quietly split your totals. Pick a convention once and never mix.
| Parameter | Job | Example value |
|---|---|---|
| utm_source | Where the visit came from | qr |
| utm_medium | The channel type | |
| utm_campaign | The campaign or print run | spring25 |
| utm_content | The exact placement | front-window |
One cost of UTM tags is characters. A 42 character URL fits a Version 3 code at error correction level M, a 29 by 29 module grid. Add 50 characters of tags and you are past 90, which pushes the code to Version 6, a 41 by 41 grid. At the same print size the modules come out about 30 percent smaller, which hurts scans from a distance and on older cameras. If a dense code starts failing, the checklist in QR code not scanning fixes applies, or skip the problem entirely with the redirect method below.
Per-location codes: one code per poster
One shared code tells you the campaign worked. Ten separate codes tell you which of ten placements worked, and that is where the real decisions live. Keep utm_source, utm_medium, and utm_campaign identical across the batch and change only utm_content per spot.
- Front window poster: utm_content=front-window
- Counter card by the register: utm_content=counter-card
- Service van door decal: utm_content=van-door
- Flyer print run A: utm_content=flyer-a
Building ten tagged URLs by hand invites typos, and one wrong ampersand silently corrupts a row of data. Put the finished URLs in a spreadsheet column and run them through the QR code generator from an Excel list to get every code in a single pass. If the codes go onto products, shelves, or equipment, print them as sticker sheets with the QR code for labels tool so each label carries its own placement tag.
Method 2: a short link on your own domain
Print a short URL like https://example.com/q/sale in the code and have your server answer it with a redirect to the long tagged URL. The build takes one folder, a one-line rule per code in an .htaccess file, and about 20 minutes, and every step, including why the rule must say 302 and not 301, is already covered in create dynamic QR links yourself, so this article stays on the measurement side.
The redirect gives you two counters at once. The server access log records one line per hit on /q/sale, the rawest possible scan count, while the redirect target still carries your UTM tags, so GA4 keeps the clean session numbers. The two will not match, and the gap is informative. Expect the raw log figure to run maybe 10 to 30 percent higher than GA4, because messaging apps prefetch links to build previews and GA4 filters known bots automatically. A gap that suddenly widens usually means a bot found the URL, not that a poster went viral.
A short URL also shrinks the code itself. That 26 character link fits a Version 2 code at level M, a 25 by 25 grid that scans reliably even at small print sizes. And because the printed code never changes, you can retarget the destination years after the ink dried.
What paid dynamic QR services actually sell
A dynamic QR subscription is the redirect method running on someone else's domain. The service prints its short URL into your code, logs each hit before redirecting, and shows you that log as a dashboard: scan counts, timestamps, device type, and city-level location estimated from the IP address. Typical pricing runs from roughly 5 to 35 dollars per month depending on code and scan limits.
The dashboard is convenient, but the mechanism is identical to your own redirect, and there is a structural risk: the printed code points at their domain, not yours. If the subscription lapses or the company folds, every printed code dies at once, a failure mode covered in detail in do QR codes expire.
| Method | Cost | What gets counted | Edit destination after printing | Works without a provider |
|---|---|---|---|---|
| UTM plus GA4 | Free | Sessions, known bots filtered | No | Yes |
| Own domain redirect | Hosting you already pay for | Raw log hits plus GA4 sessions | Yes | Yes |
| Paid dynamic service | Roughly $5 to $35 per month | Scans in their dashboard | Yes | No |
A short privacy note
Scan tracking is ordinary web analytics and follows the same rules. GA4 does not log or store IP addresses, but where GDPR or similar law applies you still need consent before analytics cookies fire. Your own server logs do store full IPs, so truncate the last octet or set a short retention window if you keep them long term.
Two things to avoid: never put personal data in the URL, since anything in a URL ends up in logs everywhere it passes, and never label utm_content with a customer name. A tag like van-door measures the poster, not the person, and that is all you need.
Start counting this week
Both free methods together take under an hour and answer the only question that matters: which printed code earns scans and which one is wallpaper. More build-it-yourself walkthroughs live in the guides section, and the full set of generators, from Wi-Fi codes to asset tags, is in the QR tools hub.
