Skip to content
SmallQRCode

How to Track QR Code Scans (Free, Without a Dynamic QR Service)

3 min read · updated 2026-09-11

"QR codes with scan tracking" is the feature QR platforms charge monthly for. Here's the part they don't advertise: if the code points at a page you control, you can count scans yourself, for free, with Google Analytics — no dynamic QR service, no subscription, no vendor who can switch your printed codes off.

The method: UTM tags. You add small parameters to the destination URL, the code carries them, and your analytics sees exactly which code was scanned, from which print run, on which date range.

What you need

  • A QR code pointing at a page on a website you control (your site, your shop's site — somewhere with your analytics tag installed). This method can't see codes pointing at someone else's page.
  • Google Analytics 4 on that site (or any analytics tool that reads UTM parameters — Plausible, Matomo and Fathom all do).

Step 1: Build the tagged URL

Take your destination and add three parameters. For a restaurant's menu:

https://yourrestaurant.com/menu?utm_source=qr&utm_medium=printed&utm_campaign=table-tents
Parameter What it means Example values
utm_source Where the scan physically came from qr, qr-flyer, qr-packaging
utm_medium The marketing channel printed, poster, direct-mail
utm_campaign Which campaign / print run table-tents, spring-promo, menu-2026

Google's Campaign URL Builder builds these if you'd rather not type them.

One rule before you generate the code: the tagged URL is longer than the bare one, and longer URLs make denser QR codes. Keep the parameters short (utm_campaign=tables, not utm_campaign=restaurant_table_tent_campaign_2026). If the URL is getting unwieldy, shorten it first — the URL QR code guide covers the trade-offs.

Step 2: Generate the QR code with the tagged URL

  1. Open the URL QR code generator
  2. Paste the full tagged URL — parameters included
  3. Download, print, deploy

Scans of this code are now distinguishable from every other visit to that page.

Step 3: Read the scans in GA4

  1. Open GA4 → Reports → Acquisition → Traffic acquisition
  2. Look for the Session source / medium row qr / printed (or whatever you chose)
  3. Filter or search by your campaign name to isolate one print run

That's the scan count: sessions where utm_source=qr. From there GA4 gives you everything it gives you for any traffic: what scanners did next, how long they stayed, whether they converted.

Counting unique codes separately

Give each physical code its own campaign (utm_campaign=table-tent-front, utm_campaign=table-tent-patio) and you can compare placements — front window vs. patio tables — in one report.

If you use a URL shortener

Shorteners work fine, but check whether yours preserves query parameters through the redirect (most do; some strip them — test once before printing 5,000 flyers). And note that a shortener's own click stats can be a free fallback scan counter if you don't run analytics at all.

What this method can and can't tell you

Can: total scans, scans per print run, scans over time, what scanners did afterward, device, country. For almost every real question — "did the flyer work?", "which table tent gets scanned more?" — that's the answer.

Can't: individual scans of codes pointing at pages you don't control (Wi-Fi codes, plain-text codes, someone else's site), and offline "scan then what" behavior beyond your site. That's true of dynamic QR services too — they count the redirect hop, which this method replaces; they don't know any more about the scanner than your analytics does.

Why this beats paying for "trackable QR codes"

A dynamic QR service inserts its server between your code and your page: the code points at their redirect, they count the hop, then forward with your UTM tags anyway. You're renting a click counter on top of the free method — and the expiry problem comes with it: stop paying, and every printed code stops working. Your own UTM-tagged static code counts the same scans and can never be switched off.

Related