QR code tracking
Measure what happened offline, without following anybody.
Make a code to try it with
Free, no account, and the code never expires. Nothing you type is uploaded.
Print is normally unmeasurable. You put a poster up, sales move or they do not, and the connection between the two is a guess. A tracked QR code closes that loop: every scan is a request, and a request can be counted, so the poster becomes the one part of your offline spend with a number attached to it.
What you get is a count over time, a breakdown by country and region, a split by device kind and operating system, and the referrer where one is sent. Enough to answer the questions worth asking — is this placement working, did the campaign move anything, are people scanning at lunchtime or on the way home.
What you do not get, deliberately, is anything that identifies the person holding the phone. That is not a limitation we worked around; it is the design. The interesting questions about print are about aggregate behaviour, and answering them does not require knowing who anybody is.
How a repeat scan is recognised without an identifier
Counting total scans is easy. Distinguishing forty people scanning once from one person scanning forty times is the part that usually involves a cookie or a stored address, and we do neither.
Instead, each scan is reduced to a one-way hash of the date, the code, the requesting address and the browser signature, combined with a secret key, and only the first sixteen characters are kept. The address itself is discarded in memory and never written anywhere. Two scans from the same phone on the same day produce the same value, so the second is not counted as a new visitor.
Because the date is part of the input, the value changes at midnight. Tomorrow the same phone produces something unrelated, which means the record cannot be used to follow anyone from one day to the next even by us.
What the numbers can and cannot tell you
Country and region come from the network, not from the device, and they are accurate at the level of a country and vague below it. Treat a city-level figure as a hint.
Device and browser come from what the phone announces about itself. It is reliable for the split between iOS and Android, and less so for exact versions.
One number needs care: a scan is not a visit. Some camera apps prefetch a link to show a preview, which registers before anyone has decided to go there. If a figure looks impossibly high for the number of posters, that is usually why.
Attaching a scan to a campaign
A code can carry UTM parameters, which are appended to the destination when the scan is resolved. That makes the traffic identifiable in whatever analytics the destination site already uses, so a print campaign shows up next to the digital ones instead of being lumped into direct traffic.
Grouping codes into a campaign gives the same view one level up: every poster, flyer and van in a campaign rolls into one total, while each still reports separately, so you can tell which placement did the work.
Questions people ask
Do you store the IP address of people who scan?
No. It is used in memory to compute the daily hash that separates repeat scans from new ones, and then discarded — it is never written to a database, a log or an analytics store.
Do I need a cookie banner for this?
We set no cookie on the person scanning and store nothing on their device, which is the thing consent banners exist to cover. Your destination page is a separate matter and follows whatever rules already apply to it.
How quickly do scans appear?
Within about a minute. The count is written asynchronously so it never delays the redirect, and the dashboard reads a live figure for today alongside the stored history.
How long is the history kept?
Individual scan records are kept for 90 days. Daily totals per code, country and device are kept for as long as the account exists, and they are what the analytics views are built from.
Can I see who scanned?
No, and neither can we. There is no identifier in the data that survives the day it was created, which is a deliberate constraint rather than a missing feature.
Related generators
Need to change it after printing?
That is a dynamic code — and ours keeps redirecting even if you cancel.