QR code tracking: how to track scans, and what the numbers mean

Give each store, poster or page its own code, group them in folders, and get the numbers out by CSV or API. Then read them honestly.

You track QR code scans by using a dynamic QR code: the code points at a short link, the short link redirects to your page, and each scan is counted as it passes through. To learn which placement works, give each one its own code. A static code sends the phone straight to your link with nothing in between, so there is nothing to count.

Track each placement with its own code

One code on every poster tells you that posters got scanned. One code per poster tells you which poster. The same holds for a code per store, per table, per page of a booklet, or per box. Codes are unlimited on every TangoQR plan, so a code per placement costs the same as one code.

  • Name each code for where it lives. "Front window", "Table 12", "Page 4".
  • Put related codes in a folder. One folder per store, campaign or client. A code sits in one folder at a time.
  • Read the folder totals. The account report lists scans per folder, and you can filter the whole report to one folder.

All of that is on the free plan as well as Pro. If you are setting up many codes at once, you can make them from a pasted list or a spreadsheet, up to 1,000 at a time.

How to track QR code scans, step by step

  1. Make the code dynamic. Create it with a service that routes through a redirect you control, such as TangoQR. That redirect is what makes each scan countable.
  2. Print and share it. Packaging, posters, menus, listings. Tracking works the same everywhere, because it happens at the redirect and not in the image.
  3. Read the scan report. Open the code to see how many times it was scanned, when, from which countries, and on what kind of device.
  4. Already printed a code? Check it with the QR code analytics checker. If it is static, its scans cannot be tracked. Print a dynamic replacement at the next reprint.

Compare folders: which store pulls

Once each placement has a code and each group has a folder, the comparison is a table: folders down the side, scans across. Open the account report, pick a date range, and read the per-folder rows. Filter to one folder to see its codes ranked against each other.

To take the numbers elsewhere, use Export CSV on the analytics page or the API (GET /api/public/v1/analytics for the account, /codes/{token}/analytics for one code). Both give you rows by code, by day, or by scan. A per-scan row carries the time, the code, its folder, the country and the device class. It never carries an IP address or a user agent, because we do not store them. Timestamps are UTC, and per-scan rows go back 90 days.

What the free plan shows

Every scan is recorded on every plan. What the free plan limits is the detail you can see. For a code's first 50 scans you get everything: the daily chart, countries, devices and time of day. Past 50 scans, a free code's detail is left out of reports and exports. The code keeps redirecting, its total keeps counting, and it still counts toward your folder and account totals. Pro shows the detail on every code, including the scans recorded while you were on free.

Tracking happens at the redirect, not in the image

A dynamic code encodes a short URL you control. A phone scans it, asks that short URL where to go, and the server answers with an HTTP 302 and the real destination. That single request is the entire measurement surface. Everything a scan report can ever tell you has to be readable from one HTTP request: when it arrived, which address it came from, and whatever the browser volunteered about itself in its User-Agent header. No cookie, no second visit, no script running on the scanner's phone.

That sets a limit worth knowing early. A 302 is cacheable when the response says it is, so if the redirect can be cached, a repeat scan may be answered from a cache and never reach the server at all. It is then invisible, permanently. Our redirect answers with Cache-Control: private, no-store for exactly this reason: a faster redirect that quietly undercounts is not a better redirect.

What each metric means

  • Total scans. One count per scan that reached the redirect. It counts scans, not people: the same phone scanning twice counts twice. Link previews, crawlers and scripts that say what they are do not count, and neither does a request that only checks whether the link works.
  • Unique devices. The number of distinct devices, where a device is a one-way keyed digest of the address and the User-Agent. We keep the digest and neither of the two things it was made from. It is a proxy and it errs in both directions: a cafe full of phones on one network can collapse toward a single device, and one phone that moves from wifi to cellular can split into two.
  • Country. Resolved from the request address by Cloudflare, which hands us a two-letter country code. Country is the whole resolution. We do not store a city, because we never receive one.
  • Device class. The User-Agent string matched into five coarse buckets: mobile, desktop, tablet, bot, unknown. Only the bucket is kept. The bot bucket is the one that matters: a request filed there is recorded, shown in the device chart, and left out of every count.
  • Time of day. Twenty-four hour buckets, in UTC. Not the scanner's local time and not yours.
  • Scans over time. Daily buckets, also UTC, with empty days present as zero so a gap reads as a gap instead of disappearing.

Check a code before you trust anyone's numbers

You can establish whether a QR code is trackable at all in about thirty seconds, with nothing printed and no account anywhere. Run this against your current provider before you compare dashboards.

  1. Decode the code to read the URL inside it. Our QR code URL checker does it in your browser.
  2. If that URL is your final destination, the code is static. Stop here: nobody can count its scans, including whoever sold it to you.
  3. If it is a short URL on the provider's domain, ask the URL what it does: curl -sI https://tgo.sh/EXAMPLE. A trackable code answers 302 with a Location header pointing at the real destination.
  4. Read the Cache-Control line in that same response. no-store means every scan reaches the server and gets counted. A long max-age means repeat scans can be served from a cache and go uncounted.

Step four is the one nobody runs, and it is the one that decides whether the totals in a dashboard are counts or estimates.

What scan data cannot tell you

  • A scan is not a person. The same phone scanning twice counts twice. Unique devices is a floor on your audience, never a headcount.
  • Link previews are not scans. Paste a short link into Slack, WhatsApp or iMessage and the app fetches it to build the preview card. Nobody scanned anything, so it does not count toward the total, and on the free plan it does not use up one of a code's first 50 scans. You can still see it: it is the bot bar in the device chart. A preview that does not say what it is can slip through and count.
  • A region is a country. "Approximate region" in most marketing copy means a country code. Ours does too. Treat any city-level claim in this category with suspicion, and ask which header it came from. To compare two stores in one city, give each store its own code.
  • The clock is UTC. A dinner rush in California lands in the 01:00 and 02:00 buckets. Convert before you draw a conclusion about human behaviour.
  • The trail stops at the redirect. We know a phone asked where to go. Whether it arrived, read the menu, or bought anything happens on your site, where your own analytics live. Tag the destination with UTM parameters if you need to join the two.

Looking for the codes you scanned yourself?

"Scan history" means two different things and they have nothing to do with each other. If you want the history of scans on a code you own, that is everything above. If you are trying to find a QR code you scanned with your own phone last week, that is a phone question rather than a QR code question, and we answered it separately in where to find QR codes you've scanned.

Retention is the number to compare

Tracking comparisons are usually feature checklists. The number that decides whether you can answer a question in six months is how long the provider keeps the data, and it is generally printed nowhere near the word "analytics". The table below is what we found when we went looking.

Bitly is the honest comparison here because it is the strongest product in the category, and there are real reasons to choose it: a UTM builder, campaign grouping, and integrations with HubSpot and Salesforce. If you manage hundreds of links across a marketing team, that is worth paying for. If you printed a code on a menu and want to know whether anyone scanned it, the retention row is the whole story.

Every TangoQR code records scans from the moment it exists, on every plan. The counts are kept for as long as the code exists: totals, and scans by day, hour, country and device class. The individual scan rows are kept for 90 days and then folded into those counts, which is why a per-scan export goes back 90 days and a chart goes back to the code's first scan. Upgrading later shows history that was being collected the whole time.

What one scan records, and how precise it is

Field Where it comes from Precision
Time The server clock when the redirect is hit To the second, stored and bucketed in UTC
Country Cloudflare's CF-IPCountry request header Country only, two letters. No city is received or stored
Device class The browser's User-Agent header, matched into five buckets mobile, desktop, tablet, bot, unknown. The header itself is not stored
Device A one-way keyed digest of the connecting address and the User-Agent Used only to count distinct devices. Neither the address nor the User-Agent is stored
Total scans One count per scan that reaches the redirect Exact, repeats included. Link previews, crawlers and scripts are left out
Unique devices Distinct device digests A proxy. Shared networks collapse it, roaming splits it
Time of day The hour read off the scan timestamp 24 buckets in UTC, not the scanner's local time

Source: How TangoQR records a scan

What you can export, on every plan

Rows What each row carries Limits
By code Code, name, folder, short link, destination, created date, lifetime scans, scans in the date range One row per code. A free code past 50 scans keeps its row and lifetime total, without the date-range count
By day Date, code, name, folder, scans A code past 50 scans on the free plan is left out
By scan Time (UTC), code, folder, country, device class The last 90 days. Never an IP address or a user agent. A free code past 50 scans is left out

Source: TangoQR CSV export and analytics API. One export holds up to 100,000 rows

An example report for one code over 30 days

Line Example value How to read it
Total scans 412 Scans that reached the redirect, repeats included and bots left out
Unique devices 287 Distinct device digests. A floor on people, not a count
Last scan 3 hours ago The freshness signal. Silence here is the useful alarm
Top country US, 301 scans Country resolution. The remaining 111 are spread or unknown
Busiest hour 18:00 UTC Convert to local time before concluding anything about behaviour
Device mix 362 mobile, 31 desktop, 19 tablet, 25 bots Bots are link previews and crawlers: shown here, not in the total
Scans over time 30 daily buckets Shape beats total: a launch spike and a steady trickle differ

Source: Illustrative. The lines and their meanings match the real per-code report; the values are invented so the shape is readable

How long QR scan analytics are kept, verified 8 October 2026

Plan Price How long scan data is kept
TangoQR Free $0 Counts for the life of the code, per-scan rows for 90 days. Full detail for a code's first 50 scans, total scans always
TangoQR Pro $10/mo Counts for the life of the code, per-scan rows for 90 days. Full detail on every code, no scan limit
Bitly Free $0 No click or scan analytics for links or QR Codes
Bitly Core $10/mo, billed yearly 30 days
Bitly Growth $29/mo, billed yearly 4 months
Bitly Premium $199/mo, billed yearly 1 year

Source: Bitly's own pricing page and its Free Plan post, both checked 8 October 2026

Common questions

Can you track QR code scans?

Yes, if the code is dynamic. A dynamic code points through a redirect, and the redirect counts each scan as it passes: how many, when, from which country, and on what kind of device. A static code encodes the destination directly, so its scans never touch a server you can see and cannot be tracked by anyone.

Can I see which store or location a scan came from?

By placement, yes: give each store, poster or page its own code and read the scans per code, or per folder. By the scanner's own location, only to the country. A scan carries a two-letter country code and nothing finer, so two stores in one city are told apart by their codes, not by where the phone was.

Can you track a static QR code?

No, and no provider can. A static code has the destination encoded in the pattern, so the phone goes straight there and no server you can see is involved. There is nothing to instrument after the fact. This is why the static or dynamic decision has to happen before the print run, not after.

Do I need to add anything to my website to track scans?

No. Measurement happens at the redirect, one hop before the browser reaches your site, so it works even if your destination is a PDF or a page you do not control. The flip side is that your own analytics will not label that traffic as a QR scan on its own. Add UTM parameters to the destination if you want the two reports to line up.

Does QR code tracking identify who scanned my code?

No. A scan record is a timestamp, a two-letter country code, a device class, and a one-way digest used only to count distinct devices. We do not store the IP address or the browser's user agent. There is no name, no phone number, and no cross-site tracking. It is enough to tell you that scans are arriving from these countries on these devices at these hours, and not enough to tell you anything about a person.

Can I start tracking a code I already printed?

Only if it was dynamic to begin with. If it points through a redirect, its scans have been recorded all along and are waiting for you. If it was static, the printed pattern points straight at your destination and cannot be retrofitted. Check which kind you have with the QR code analytics checker before you assume either way.

Why is my scan count higher than the number of people I watched scan it?

Usually because one phone scanned more than once. Repeat scans from the same phone each count, and a person who scans, loses the page, and scans again counts twice. Link previews from chat apps and crawlers are left out of the count, but one that does not say what it is can slip through. Compare the total against unique devices to get a sense of the gap.

How many scans does a free TangoQR code track?

All of them. Collection is never limited or throttled by plan. What the free plan limits is the detailed view: the country, device and time-of-day breakdowns stay clear for a code's first 50 scans, and after that the running total keeps showing while the detail is left out of reports and exports until you upgrade. The data underneath is still being recorded, so upgrading shows you the history rather than starting a new one.

Sources

Keep reading

Try it here

Make a QR code you can change later

Every TangoQR code is an editable redirect, free to start. Print once, repoint forever.

  • Keeps redirecting forever, even if you cancel
  • No account needed to start
  • Editable for each code's first 50 scans, free
  • PNG and SVG download

← All posts