Blog

QR codes for offline campaigns: track every flyer, box and booth

How to put QR codes on print, packaging and event materials so every scan shows up in your analytics: one tagged code per placement, the right error correction, the four-module margin, and a test before you print.

A flyer does not tell you it worked. Neither does a sticker on a shipping box or a sign at a market stall. Put a QR code on it and it still might not, because a scan with no tags arrives in your analytics looking like someone typed your address from memory.

The fix is small and it has to happen before the print run: tag the link, make one code per placement, and test it. This guide covers the whole routine, and our free QR code generator does the tagging and the code in one step, in your browser.

Why an untagged code is a wasted code

When someone scans a code, their phone opens the link directly. There is no page before it, so there is no referrer to say where the visit came from. Google Analytics then has nothing to go on and files the visit as Direct, the channel it describes as people arriving through a saved link or by typing your URL. Your flyer’s visits end up mixed in with everyone who bookmarked your site.

UTM tags fix that. They are labels added to the end of the link, and Google says to always set three of them: utm_source, utm_medium and utm_campaign. Add them to the link inside the code and every scan carries them in.

One code per placement

The most useful habit is also the simplest: never reuse a code across placements. If the same code sits on the counter card, the window poster and the receipt, you learn that QR codes got scans and nothing about which one earned them.

Give each placement its own tagged link. Keep the campaign the same and change the content tag:

  • utm_source=print, utm_medium=qr, utm_campaign=spring_launch, utm_content=window_poster
  • the same, with utm_content=counter_card
  • the same, with utm_content=receipt

For packaging, use the content tag for where on the pack it sits (box-insert, back-label). For events, name the event in the campaign and the spot in the content (booth-banner, handout). Keep every value lowercase, because Google treats values as case sensitive: Print and print would show up as two sources.

If you already use our UTM link builder for ads, the rules are the same. The QR generator applies them for you: it keeps any parameters already in your link, replaces old UTM values and keeps a #section anchor at the end.

Where the scans show up in Google Analytics

GA4 sorts visits into channels using rules on the source and medium. Its default channel group has channels for email, SMS, social, search, referral and more, but none for print. A medium like qr matches none of the rules, so those visits land in Unassigned, which is what GA4 uses when no rule fits. Two catches in the same table: a source named after a social site (say instagram) sends the visits to Organic Social, and a campaign name with shop or shopping in it, like utm_campaign=summer_shop, sends them to Organic Shopping. A neutral source such as utm_source=print and a campaign like utm_campaign=spring_launch avoid both.

That is fine, and better than Direct: the visits are separate and fully labelled. Filter any report by the campaign or the source and medium, and each placement is its own row. Just decide on one spelling for the medium and stick to it, so all your print sits together.

Pick the error correction level on purpose

Every QR code carries spare data so it still scans when part of it is damaged. Denso Wave, the company behind the QR Code, lists four levels, restoring roughly 7% (L), 15% (M), 25% (Q) and 30% (H) of the code. It also notes that Level M is the most often picked, that Q or H suit places where codes get dirty, and that a higher level makes a bigger code.

In practice:

  • M for flyers, menus, posters and anything that stays clean.
  • Q or H for packaging that gets handled, shipping labels, outdoor stickers, and anything that might be scuffed, bent or partly covered by a thumb.
  • L only when a long link will not fit any other way, and then consider a shorter link instead.

Leave the white border alone

The empty frame around a code is part of the code. Denso Wave’s guide to code size is blunt about it: “QR Code requires a four-module wide margin at all sides of a symbol.” A module is one of the small squares. It is tempting to crop that margin to make a layout tidy, or to set the code on a patterned background. Both eat into the clear frame the standard asks for, so do neither.

Our generator starts with a four-module margin and warns if you go below it.

Work out the printed size

A QR code comes in 40 grid sizes called versions. Version 1 is 21 by 21 modules and each version adds 4 per side, up to 177 by 177 at Version 40. The generator shows which version your link needs. The arithmetic for print size is then simple:

printed width = (modules + 8) × module size

The 8 is the four-module margin on each side. Denso Wave’s own example uses a module of 0.254 mm: a Version 3 code is 29 modules, so 7.366 mm, and 9.398 mm with the margin.

A worked example for a flyer: your tagged link fits in Version 4, which is 21 + 3 × 4 = 33 modules. You want each module to be 0.6 mm. That is (33 + 8) × 0.6 = 24.6 mm, so plan for a square of about 25 mm. If the link needs Version 6 instead (41 modules), the same 0.6 mm modules need (41 + 8) × 0.6 = 29.4 mm. That is why short links matter: every version you add grows the square, or shrinks the modules if the space is fixed.

There is no single right module size, because it depends on how far away people stand and on their phones. The honest method is the next section.

Test it like a customer

  1. Scan the file on screen with two or three different phones, including an older one.
  2. Print a proof at real size, on the real paper if you can, and scan it from the distance people will stand at.
  3. Check the landing page on a phone. It is where every scan ends up, so it should load fast and make sense to someone who has just walked up to a poster.
  4. Check the tags arrived. Open your analytics real-time view, scan once, and look for your campaign name.

Use the SVG download for print. It is a vector, so it stays sharp at any size, and it is what a printer or a design tool wants.

Colours and branding

A code in your brand colours is fine as long as the modules stay clearly darker than the background. Pale grey on white, or a light code on a dark box, is where scans start to fail. The generator measures the contrast between your two colours and warns when it is low or reversed. Still, trust the proof print over the preview.

Static or dynamic?

A static code holds your link directly. It works for as long as that page exists, with no account, no subscription and no expiry. A dynamic code holds a short link to a redirect service, which lets you change the destination later and count scans on its side, but the code stops working if that service goes away.

For most printed campaigns, a static code with UTM tags is enough: the scans are counted in your own analytics, where the rest of your traffic already lives. If a destination might change after printing, point the code at a page on your own site that you control, and change that page instead.

A checklist before the print run

  • One tagged code per placement, with source, medium and campaign set, all lowercase.
  • Error correction at M for clean surfaces, Q or H for anything handled or outdoors.
  • A four-module white margin, untouched by the design.
  • Printed size worked out from the version and the module size.
  • A real-size proof scanned on several phones, and the visit seen in analytics.

Ready to make them? Open the QR code generator, tick Add UTM tags, and download an SVG for each placement.

Where Hermoso fits

Hermoso is an AI marketing agent. It researches the ads already working in your market, makes on-brand image and video ads, posts and schedules to your own social accounts, and runs paid campaigns on your own ad accounts. It works in the web app, or inside Claude, ChatGPT and Cursor through its MCP server. The QR codes stay a free tool, with no sign-up.

Questions people ask

How do I track scans from a printed QR code?

Add UTM tags to the link before you make the code: utm_source, utm_medium and utm_campaign at least, and utm_content to tell placements apart. Every scan then arrives in Google Analytics with those labels. Without tags, a scan usually shows up as Direct traffic.

Which error correction level should I use for packaging?

Q or H. Denso Wave, the company behind the QR Code, says those suit places where codes get dirty, and packaging gets handled. Use M for clean surfaces like flyers and menus.

How big should the white border around a QR code be?

Four modules on every side. Denso Wave states that QR Code requires a four-module wide margin at all sides of a symbol.

Where do QR code visits appear in GA4?

GA4 has no print channel. With a medium like qr and a neutral source and campaign name, the visits land in Unassigned, where they stay separate and fully labelled. Filter by campaign or by source and medium to see each placement. A campaign name containing shop sends them to Organic Shopping instead.

Do static QR codes expire?

No. A static code holds the link itself, so it works as long as the page it points to exists. Only dynamic codes, which go through a redirect service, depend on that service staying up.