Someone prints 500 flyers with a QR code, the campaign runs for a month, and then the code starts opening an error page. The flyers are still on the wall. The natural conclusion is that "the QR code expired". It didn't, and understanding why tells you how to make sure it never happens to you.
A QR code is ink. Ink has no expiry date.
A QR code is a way of writing data as a grid of squares, defined by the ISO/IEC 18004 standard. The squares encode text, usually a URL, plus error-correction data so the code still reads when part of it is damaged or covered. There is no timestamp in the format, no licence check, no connection to any server. A scanner reads the squares, decodes the text, and hands it to your phone. That's the whole transaction.
So the code you printed in 2019 decodes to exactly the same text today. Whether that text still leads anywhere is a different question, and that's where every "expired QR code" story comes from.
Two kinds of code, two ways to break
What's written in the squares depends on how the code was made.
A static code contains the final destination itself: https://your-site.com/menu, or the Wi-Fi name and password, or a phone number. Nothing sits between the scanner and the destination.
A dynamic code contains a short link on the generator's domain, something like qr-generator.example/x8Kq, which redirects to the real destination when scanned. That indirection is what makes the code editable (change the redirect, not the print) and measurable (every scan passes through a server that can count it). It's also a dependency: the redirect has to keep working for as long as the print exists.
| Static code | Dynamic code | |
|---|---|---|
| What the squares contain | The destination | A redirect link on the generator's domain |
| Stops working when… | The destination disappears | The redirect service stops answering |
| Depends on a company staying in business | No | Yes |
| Depends on a subscription | No | Usually, yes |
| Can be fixed after printing | No, reprint | Yes, re-point the link |
A static code fails only when the destination fails. The page gets deleted in a site redesign. The domain isn't renewed. The restaurant changes its Wi-Fi password. In each case the code is fine and the thing it points to is gone.
A dynamic code fails when the service fails, and this is the common case, because dynamic codes are what most online generators produce by default, and most of those generators are businesses with a free trial.
Why "free" dynamic codes stop working
Open a popular QR generator, paste a URL, download the code. In many tools what you just made is a dynamic code on a free trial. Trial lengths vary: some vendors give 14 days, some 15, some 30; some cap free codes at a number of scans. When the trial ends, the redirect behind your code is switched off, and the code opens an error page or the generator's upsell page, until you subscribe.
The vendors are open about this on their own blogs, where "do QR codes expire?" is a standard article: the code didn't expire, the service behind it did, and reactivating the plan usually restores it. The problem is that the print run happened before anyone read that paragraph.
The three things to check before printing a dynamic code from any service:
- What happens when the trial or plan ends. Look for words like "deactivated", "paused" or "archived". If the answer is "your codes stop working", assume they will, at the worst time.
- Scan limits. A code capped at 50 or 100 scans on a free plan is fine for a test and useless on a shop window.
- Who owns the domain in the code. If the short link lives on the generator's domain, you can't take it with you. If the company shuts down, every printed code they ever issued goes dark at once.
How to check a code you already printed
Scan it with your phone's camera and read the URL that appears before you tap it.
If it's your own domain, you have a static code. Open it; if the page loads, you're fine. If it doesn't, fix the page (or set up a redirect from the old URL to the new one) and the printed code starts working again without reprinting.
If it's a short URL on someone else's domain, you have a dynamic code. Open it and confirm it lands where you expect. Then log into that generator and check the plan status, the scan count and the expiry date on the code. If you can't remember which generator made it, the domain in the link tells you.
Do this for every code that's still physically in the world: menus, posters, packaging, business cards, the sticker on the van. Put a reminder in the calendar to do it again in six months.
How to print a code that lasts
If you don't need to change it or count scans, use a static code pointing at a URL you control. The free crisp generator makes static codes entirely in your browser; nothing is uploaded and there's no account, so there's nothing that can lapse. The code is as permanent as the page it points to, so point it at a URL you'll keep: your-site.com/menu, not your-site.com/2026/autumn-menu-v3.pdf.
If you do need to edit or measure, use a dynamic code from a service that promises not to expire it. This is what crisp dynamic codes are for: each one wraps a short link you can re-point any time, with scan counts in the dashboard, and the link keeps redirecting on every plan, including Free, even if you cancel. That isn't a marketing line; it's section 4 of the Terms of Service, which also protects codes already printed from any later change to that section, and commits us to 12 months' notice with everything still redirecting if crisp ever closed.
Either way, print the destination as text under the code. crisp.to/menu under the squares lets a person check where the code leads, and gives them a way in if their camera won't scan. It also makes a code harder to hijack with a sticker, which is the one QR "expiry" nobody talks about: someone covering your code with theirs.
And use enough error correction. Level M (15% damage tolerance) is the right default for print; go to H (30%) if you're putting a logo in the middle or the code will live outdoors. Both are options in the free generator.
What "never expires" should mean when you read it
Every generator now claims its codes "never expire", because every generator knows this is the question people search for. Read the claim carefully. "Static codes never expire" is trivially true and says nothing about the dynamic codes the same tool pushes you towards. "Dynamic codes never expire on paid plans" is a subscription with extra steps. The only version of the promise that protects a printed code is one that holds when you stop paying, and the only way to know whether a vendor means that is to find it in their terms.