guide

How to put a form behind a QR code and see where the scans came from

September 23, 2026 ・ Halict Editorial

A QR code that opens a form is a solved problem. Any generator will turn a URL into a square in a few seconds, and it will work when tested from a desk. The failures happen later and they are all mundane: the code is printed too small to scan from where people stand, the destination has to change after two hundred posters are already on walls, and after three weeks there are ninety responses and no way of telling which poster produced any of them.

None of those is a QR code problem. They are consequences of treating the code as the deliverable rather than as one end of a link that has to survive contact with a corridor.

The code is a URL in a picture, and nothing else

This is worth stating plainly because a lot of confusion follows from forgetting it. A QR code contains text. When that text is a URL, the phone camera offers to open it. There is no tracking, no identity and no state inside the code. Whatever you want to know about a scan has to be encoded in the URL itself or observed at the destination.

Two consequences follow immediately.

The code cannot be changed once it is printed. Whatever URL went into it is in it permanently. If that URL is the form's own address and the form is later replaced, every printed code is dead.

Longer text means a denser code. QR symbols come in versions from 1 to 40, starting at 21 by 21 modules and rising to 177 by 177, with four extra modules per side at each step, as Denso Wave documents. More characters require a higher version, which means more modules squeezed into the same printed square, which means each module is physically smaller and harder for a camera to resolve. A long URL full of tracking parameters is not free. It is paid for in scan reliability at distance.

Both problems have the same fix, and it is the first thing to set up.

Point the code at a link you control

Encode a short URL that you own and that redirects to the form, rather than the form's address itself.

This costs nothing and buys two things that are hard to obtain any other way. The destination stays changeable, so a form that gets rebuilt, moved, closed or replaced next year does not orphan the printed material. And the URL stays short, so the code stays coarse and scannable.

A path on your own domain is the better choice where it is available, because it also tells a cautious person where the code leads before they tap. Scanning a code and seeing an unfamiliar shortening service in the preview is a reason people abandon, particularly for anything involving personal details.

Set up one redirect per physical placement rather than one for the whole campaign. This is the decision that makes the next section possible, and it is almost free at the point of setup and impossible to retrofit.

There is a trap here worth naming. Many generators offer a dynamic or editable code, which means the printed code points at their service and they perform the redirect. The editability is real and useful, but the dependency is total: if that account lapses or the service changes its terms, every printed code stops working and there is nothing to be done about it, because the printed square points at somebody else's domain. Some services offer this free for a trial period and then require a subscription to keep the redirect alive. Check what happens to an existing code when the plan ends before committing printed material to it, and prefer a redirect on a domain you control where that is an option.

One code per place, so the scans can be told apart

The question that gets asked afterwards is always the same: which poster worked. Answering it requires a decision before printing, not analysis afterwards.

Give each placement its own identifier and carry it through to the response. The mechanism is a query parameter on the destination URL, such as a source field appended by the redirect, which the form reads into a hidden field and stores alongside the answers. The result is that every response arrives already labelled with where it came from, and no analytics work is needed to find out.

Choose identifiers that will still mean something in six months. The building and the position beat a serial number: reception desk, staff room noticeboard, second floor lift lobby, the flyer handed out at the March open day, the back of the receipt. A code labelled qr3 tells nobody anything by the time the results are being read.

Print a different code for each placement even where the destination is identical. The codes look the same to a human and cost nothing extra to generate, and the alternative is guessing.

Two things to note about what this can and cannot tell you. It records scans that resulted in the form being opened, which is the number worth having. It does not record scans where somebody pointed a camera and then changed their mind, because nothing reaches you. And it cannot distinguish two people who scanned the same code, which is fine, because the point is to compare placements rather than to identify individuals.

Keep the printed code scannable where people actually stand

Most codes that fail in the field fail for physical reasons, and the constraints are specific.

Leave the quiet zone. A QR symbol requires a clear margin four modules wide on all four sides, with nothing printed in it. Denso Wave's guidance on determining the code area includes that margin in the size calculation. Designers routinely crop it or run a coloured background right up to the edge, and the result is a code that reads from six inches and not from three feet.

Size it for the reading distance, not for the layout. A rough working rule used in print production is that the code needs roughly a tenth of the intended scanning distance as its width, so a code to be scanned from two metres wants about twenty centimetres. A code on a poster at the far side of a counter is not the same problem as a code on a leaflet in somebody's hand.

Choose the error correction level deliberately. There are four levels. Level M restores around 15 percent of codewords and is the one most commonly chosen, while Level Q is around 25 percent, per Denso Wave's error correction documentation. Higher correction survives smudges, staples and coffee, and costs capacity, which pushes the version up and the modules down. For a laminated sign indoors, M is sensible. For something that will be handled, outdoors or industrial, a higher level earns its cost.

Keep the contrast conventional. Dark modules on a light background, with real contrast. Inverted codes and mid tone colour pairs read on some phones and not others, which is the worst possible outcome because it looks fine in testing.

Think about where the phone will be. A code at ankle height, behind glass that reflects the ceiling lights, or on a surface people cannot approach, will not be scanned regardless of how well it is generated. Chest height, matte finish, reachable.

Print the URL underneath in text. Some people will not scan a code, some phones will not, and a short readable address costs one line.

Then test from the actual position, on more than one phone, in the light that will be there. This takes five minutes and catches most of the above.

The form on the other side is being opened on a phone in a corridor

A scanned form has a different audience from a form reached from an email. The person is standing up, possibly holding something, in whatever light there is, and they decided to do this about four seconds ago. Their patience is short and measurable.

Three things matter more than usual.

Length. Every field costs completions here more than it does anywhere else. Ask what is needed to act, and collect the rest later from people who turn out to matter.

No sign in. A form that requires an account to submit will lose most of a walk up audience. This is worth checking specifically, because on some platforms particular question types quietly force a sign in, file upload being the common one. Open the published form from a signed out browser on a phone before printing anything.

One thing at a time. A long scrolling page on a phone hides its own length and invites abandonment partway. Presenting one question per screen with a progress indicator suits the situation better, which is one reason the arrangement has become common for forms that are opened on phones.

The thing not to do is point the code at a page about the form. An extra tap between the scan and the first question loses a share of everybody, and the QR code has already done the work of expressing intent.

Where the responses go decides whether any of this was worth it

The placement labels are only useful if something acts on them, and a scanned form usually produces work rather than a statistic.

A code on a maintenance sign produces a fault that somebody has to fix and report back on. A code at an event produces enquiries that somebody has to answer. A code on a receipt produces complaints and compliments, and the complaints need a reply. In each case the response is the start of a task, which means it needs an owner, a stage and a record of what was sent, in the same place as the answers.

The label makes this better rather than replacing it. Filter the list by placement and the pattern in the responses is visible: the code by the lift produces access problems, the one in the staff room produces equipment faults, and they should probably go to different people. Where a tool supports it, routing and filtering by that hidden field is the point at which the labelling pays for itself rather than just satisfying curiosity. The features list is the place to check whether hidden fields, owners and stages exist before choosing, since adding them later means moving the data.

Keep the label as an internal field rather than a visible question. Asking people to select where they saw the code produces unreliable answers and adds a field to a form that cannot afford one.

What to change first

If codes are already printed and pointing straight at a form, note the risk and do not reprint yet. Do put a redirect you control in front of the next batch, give every placement its own label, and store that label on the response. Then check that a scanned response can be assigned to somebody and replied to without leaving the list, which is what the demo of Halict walks through.

Q1. Should the QR code point directly at the form URL?

No. Encode a short address you control that redirects to the form. The code cannot be edited once printed, so a direct link means every printed copy dies if the form is ever moved or replaced, and a shorter URL also produces a coarser, more reliably scannable code.

Q2. How do you tell which poster a response came from?

Give each placement its own code and its own identifier in the destination URL, then have the form store that identifier in a hidden field. Every response then arrives labelled with where it came from. Naming the placements by location rather than by number is what makes the results readable months later.

Q3. How big does a QR code need to be?

It depends on the scanning distance, and a common print production rule of thumb is about a tenth of that distance as the code width, so roughly twenty centimetres for a two metre scan. Whatever the size, the symbol needs a clear quiet zone four modules wide on every side, which designers frequently crop.

Q4. Which error correction level should be used?

Level M, which restores around 15 percent of codewords, is the most commonly chosen and suits clean indoor conditions. Higher levels such as Q at around 25 percent survive dirt and damage better but consume capacity, which increases the symbol version and shrinks each module at a fixed printed size.

Q5. Do people need an account to fill in a form from a QR code?

They should not, and this is worth verifying rather than assuming. Some platforms force a sign in for particular question types, file upload being the usual one, which removes most of a walk up audience. Open the published form from a signed out browser on a phone before anything goes to print.

All guides

How to put a form behind a QR code and see where the scans came from | Halict