
To count QR code scans you need a dynamic QR code, because only a dynamic code routes each scan through a server that can record it. A static code has no server in the path, so the scan itself is invisible. You can still measure what happens after a static scan by adding UTM parameters to the destination and reading your web analytics.
At a glance
- Only dynamic codes can count scans. No server sees a static scan, so nothing can count it.
- Static codes are not unmeasurable, though. Put UTM parameters on the destination URL and your web analytics will show the visits — you just lose scan-level detail and anything that happens when the scan does not end in a page view.
- You get scan counts, timing, rough location, device and operating system, and campaign source.
- You do not get names, email addresses, or the identity of the person scanning. Anyone promising that is either wrong or doing something you do not want to be part of.
- All scan numbers are estimates, including the totals. Bot filtering, deduplication and coarse network fingerprints all mean a platform reports qualifying recorded scans, not every physical scan that happened. This matters when you report to a client.
- Use UTM parameters to attribute scans to a specific poster, city or channel.
How QR code tracking actually works
A dynamic QR code encodes a short link rather than your real destination:
Scan --> https://pxqr.io/a1b2c --> server records the scan --> forwards to your page
That middle step is the whole mechanism. The server sees the request, writes down what it can observe about it, and forwards the visitor onward. The redirect is fast enough that nobody notices it happened.
A static code has no middle step. The phone reads the destination straight out of the pattern and goes there directly. No server is involved, so the scan itself cannot be counted. This is not a limitation any provider can engineer around — it is how the format works.
Static codes are still measurable, just not scannable-countable
This distinction gets flattened in most guides, so be clear about it.
If your static code points at a web page, put UTM parameters on that URL before you generate the code. Your web analytics will then show the resulting visits as an identifiable traffic source. You lose:
- Scan-level timing and device data from the redirect
- Any scan that does not end in a page view — a failed load, a closed browser, a scan of a WiFi or plain-text code
- The ability to change anything afterwards, since the UTM tags are baked into the pattern
But "static means zero measurement" is wrong. It means no scan analytics, not no data.

What data you get
Everything below comes from the network request itself. Nothing requires an app, a cookie banner, or the visitor agreeing to anything.
| Data | Where it comes from | How reliable |
|---|---|---|
| Total scans | Count of recorded scans | Close, but see below |
| Date and time of each scan | Server clock | Exact |
| Country, region, city | IP address lookup | Country reliable; city approximate |
| Device type and OS | Browser user-agent string | Reliable |
| Browser | User-agent string | Reliable |
| Campaign source | UTM parameters you added | Exact, if you set them |

City-level location is genuinely approximate. It comes from mapping the IP address to a rough geographic area. It is reliable at country level, useful at region level, and should be treated as indicative at city level. Mobile networks in particular can place a visitor in a different city entirely.
What you cannot get, and why that is fine
A QR scan is an anonymous web request. You cannot learn:
- Who the person is — no name, email, or phone number
- Whether they have scanned before on a different device or network
- Their exact location
- Anything they did before scanning
If a provider claims to identify individual scanners, be sceptical and read carefully what they are actually doing.
This is a feature, not a shortcoming. Because scan tracking collects no personal identifiers, it sidesteps most of the compliance burden that follows cookie-based tracking. PixlQR anonymises IP addresses before storing them, which means the data is genuinely useful for measuring campaigns and genuinely not useful for identifying people.
Best for: measuring whether a poster, location or channel worked. Not for: building a contact list. If you need that, put a form on the landing page and ask.
Why every scan number is an estimate
This deserves a straight answer, because it will eventually affect a number you report to someone. Even your total is not a literal count of every physical scan, and any platform implying otherwise is overselling.
Three things sit between a phone scanning a code and a number appearing on a dashboard:
- Bot filtering. Link scanners, security crawlers, preview bots and messaging apps fetch URLs constantly. A platform that counted those would inflate your numbers badly, so it discards them — occasionally including something that was genuinely a person.
- Deduplication. A visitor who reloads, or whose phone requests the link twice in a few seconds, is counted once. Correct behaviour, but it means one physical scan and one recorded scan are not always the same event.
- Privacy and network effects. PixlQR anonymises IP addresses before storing them, so the fingerprint behind unique counts is deliberately coarse. VPNs, corporate networks and privacy-focused browsers change what a scan looks like on arrival, which merges some scans and splits others.
So the honest framing is: a platform reports qualifying recorded scans. That number is close enough to be genuinely useful for comparing placements, campaigns and time periods — which is what you actually need it for. It is not an audited count, and it should not be presented to a client as one.
Unique scans are looser still
To decide whether a scan is "unique," a tracking system fingerprints the request — typically from the anonymised IP address plus the device's user-agent string. It has nothing else to work with.
That produces two unavoidable errors:
Different people counted as one. Everyone on a restaurant's guest WiFi shares an IP address. Two diners on the same network with the same iPhone model look identical to any tracking system. They will often be counted once.
One person counted as several. Someone who scans on mobile data, then again on WiFi, or who scans on their phone and later opens the link on a laptop, looks like separate visitors.

Both numbers are useful, and they answer different questions:
- "Is this poster generating interest?" → total scans
- "Roughly how many distinct people?" → unique scans, treated as a ballpark
Comparing these numbers is sound. Quoting them as facts is not. "The window poster got four times the scans of the table tent" is a safe and genuinely actionable claim. "1,204 people scanned our poster" is not — you know neither that it was 1,204 nor that they were people.
How to set up tracking
- Create a dynamic QR code. Tracking is a property of the code type, not a setting you switch on afterwards.
- Set the destination to the page you want people to reach.
- Add UTM parameters if you will run this in more than one place — see the next section.
- Print and test. Scan the physical code and confirm it registers.
- Wait for real data. Your own test scans will be in the numbers, so do your testing before the campaign starts, not during it.
One thing to check on your first test: many providers filter out bot and crawler traffic automatically. That is correct behaviour, but it means a scan from a command-line tool or an automated checker may not appear. If you are testing, use an actual phone.

Once you have more than a couple of codes, the useful view is the whole portfolio ranked rather than any single code. That is what turns "we got some scans" into "the window poster is carrying this campaign."
Attributing scans to a specific campaign
A single scan count tells you a code was used. It does not tell you which poster worked.
The fix is a separate QR code per placement, each with its own UTM parameters on the destination URL:
Window poster yoursite.com/offer?utm_source=qr&utm_medium=print&utm_campaign=spring&utm_content=window
Table tent yoursite.com/offer?utm_source=qr&utm_medium=print&utm_campaign=spring&utm_content=table
Flyer, Station A yoursite.com/offer?utm_source=qr&utm_medium=print&utm_campaign=spring&utm_content=station-a
Now you can see that the window poster produced four times the scans of the table tent, and you know where to spend next time.
Why a separate code per placement, rather than one code everywhere: with one code you learn the total and nothing else. With five you learn which of five ideas worked. The cost of being wrong about placement is far higher than the cost of five codes.
Watch out for: UTM parameters make the destination URL long. On a static code that would visibly increase pattern density and hurt scannability at small print sizes. On a dynamic code the encoded short link stays the same length no matter how long the real destination is — one more reason dynamic suits print.
Connecting scans to Google Analytics
QR analytics and web analytics answer different questions. Scan analytics tells you the code was scanned. Google Analytics tells you what happened next.
Connect them with the UTM parameters above. Once the destination carries them, scans arrive in GA as an identifiable traffic source and you can follow the whole path:
Scan --> landing page --> signup --> purchase
That is the number that matters. Scans are the top of the funnel, not the outcome — a poster with 500 scans and no conversions is a worse result than one with 50 scans and 10 sales.
Mistakes that ruin your data
- Printing a static code and hoping to add scan tracking later. You cannot — and you cannot change the destination either. If you at least put UTM parameters on the URL before generating it, you keep destination-level measurement. Decide before printing.
- Using one code across every placement. You lose the only comparison worth having.
- Counting your own testing. Test before launch, not during.
- Treating unique scans as a headcount. See above.
- Reporting scans as the result. Scans are interest. Conversions are results.
- Forgetting UTM parameters and then trying to reconstruct attribution afterwards. It cannot be done retroactively.
Frequently asked questions
Can I track a QR code I already printed? Scan tracking, only if it is dynamic. If it is static you cannot add scan analytics retroactively and you cannot change the destination — but if the URL already carries UTM parameters, your web analytics is still recording those visits.
Is "total scans" the exact number of times my code was scanned? No, and treat any platform that claims otherwise with suspicion. Bot filtering, deduplication and the coarse fingerprint left by an anonymised IP mean the figure is qualifying recorded scans. It is reliable for comparison, not for auditing.
Do people know they are being tracked? The redirect is not hidden. PixlQR does not store the scanner's IP address — it stores an anonymised, network-derived location and basic device information, which is the same kind of thing any web server logs when you visit a page. No name, email or account is attached to a scan.
Does tracking slow down the scan? The redirect adds a fraction of a second. In practice a densely printed pattern affects real-world scan speed far more than the redirect does.
Can I export the data? You should be able to. PixlQR exports scan data as CSV and Excel on the Plus plan and during the trial; the free plan is dashboard-only. Whatever provider you pick, check this before you build reporting around it — data locked inside someone's dashboard is data you do not really have.
How long is scan data kept? It varies by provider, and the detail matters more than the headline number. PixlQR keeps individual scan records for 180 days, then deletes them and keeps daily aggregated totals indefinitely — so long-run trends survive, but you cannot inspect a single scan from two years ago. Ask any provider what happens after their retention window: quietly discarding the aggregates too is what breaks a year-on-year comparison.
Try it yourself
Create a dynamic QR code, scan it with your phone, and watch the scan appear. It takes about two minutes and it is the fastest way to see what the data actually looks like.
Track your first scan — free plan, no card required.
Read next
Try it: build a QR code here
An interactive builder loads in this space. If it stays empty, enable JavaScript to use it — or create an account and build your QR code in PixlQR.