Dynamic QR generator — change URL after printing, track scans
A Dynamic QR redirects through our short link to your target URL. You can change the target anytime without reprinting the QR, and see scan counts per day and per country. No signup.
Your dynamic QRs
No dynamic QRs yet. Create one above ⬆️
Why use this tool
Print the QR on a banner, then a month later swap the landing page without a reprint — log into the dashboard and update the target URL.
Total scans, last 24h, last 7d, plus breakdowns by day and country (via Cloudflare geo).
Each QR gets a secret claim-token saved in your browser. No email, no password — the token is the key.
How to use
- 1Paste the target URL and click 'Create dynamic QR'.
- 2Save the claim-token somewhere safe (1Password, Notes, text file). Lose it = lose edit + stats access.
- 3Download the PNG, print it on a banner/poster/card. Scanners hit the short link, get redirected to the target.
- 4Need to change the URL? Open 'Your QRs' dashboard → Edit → new URL → Save. Existing printed QRs still work.
- 5Track stats: the dashboard shows scan_count + 24h/7d live.
Dynamic QR vs Static QR — the difference
Static QR is the common kind: the URL is encoded directly into the pattern. Scan → open that URL. Pros: free, no server dependency, never expires. Cons: the URL cannot change — once printed, it's final.
Dynamic QR encodes one of our short links (e.g. qr-code.phanmemtonghop.com/r/aB3xY7Pq). Scanning hits the short link, then our server 302-redirects to the real target. Because the target lives in our DB, you can change it anytime.
Trade-off: Dynamic QR depends on our server. If the server is down, the QR doesn't work. We aim for 99.9% SLA and daily DB backups. The system runs on the phanmemtonghop homeserver — stable for 18+ months (see other ecosystem SaaS).
Anonymous claim-token: instead of email/password, each QR gets a secret 24-char nanoid token. You save it (the browser also caches it in localStorage). Send it with edit/stats requests. No-account = no phishing email + no verification flow.
- ✓URL editable after creation (PATCH /api/qr/:id)
- ✓Scan analytics: total + 24h + 7d + by_country + by_day
- ✓Anonymous claim-token (no email/password)
- ✓8-char short link (qr-code.../r/aB3xY7Pq)
- ✓Bot detection — crawlers don't bump the scan count
- ✓Clean 302 redirect (SEO-friendly)
- ✓Rate limit 5 QR/min/IP to deter spam
- ✓Delete QR + scan history from the dashboard
Dynamic QR use cases
Event banner Dynamic QR → swap the landing per season. Scanners 6 months later still hit the new page.
Table stickers QR → change the menu link when prices update or you switch platforms (Google Drive → real website).
Print 1000 QRs, point at Landing A in week 1, swap to Landing B in week 2 — compare conversion.
Coupon QR expires → repoint to an 'Expired' page or new voucher. Customers don't need to scan a different QR.
If a QR gets misused (scam, stale bookmark), change the target to a warning page or delete the QR entirely.
One QR per channel (Facebook, TikTok, Email) → compare scans to see which channel actually performs.
How Dynamic QR works under the hood
On create, the system generates an 8-char ID (nanoid URL-safe alphanumeric) and a 24-char claim-token. The ID + bcrypt hash of the token are stored in SQLite. You get back id + token (token is returned exactly once — after that only the hash remains).
The QR is rendered client-side pointing to https://qr-code.phanmemtonghop.com/r/<id>. On scan, the request hits a Next.js Route Handler at /r/<id>, looks up target_url in DB, increments scan_count + logs a scan_event (UA + cf-ipcountry), and returns a 302 redirect.
Editing: PATCH /api/qr/<id> with body { target_url, claim_token }. The server runs bcrypt.compare(token, hash). Match → update target_url. Mismatch → 403 Forbidden.
Anti-spam: rate limit of 5 creates/min/IP via in-memory bucket. Bot detection regex (bot|crawler|spider|preview|fetch|curl|wget) — bots still get redirected but don't bump scan_count, keeping stats clean.
Dynamic QR FAQ
I lost my claim-token — can I recover it?
No. We only store the bcrypt hash, never the plaintext. Losing the token = permanently losing edit + stats access. The QR still works (still redirects to the existing target), but you can't update it anymore. Save the token right after creation (the browser caches it in localStorage; back it up to 1Password or a text file).
If I clear my browser storage, do I lose the QR?
The QR and stats are still in our DB. But the dashboard loses sight of it — the 'Your QRs' list reads from localStorage. To recover, you need the claim-token to fetch /api/qr/:id/stats. Lose both localStorage and a backed-up token → ownership is gone.
Is the scan count accurate?
Yes. Every /r/:id GET logs a scan_event in the DB (unless the UA looks like a bot/crawler). Stats are realtime COUNT(*) of scan_events.
Where does the country breakdown come from?
From the cf-ipcountry header set by Cloudflare (DNS proxy). If the request bypasses CF (e.g. internal test), country shows '??'.
Is there a limit on the number of QRs I can create?
Rate limit of 5 QR/min/IP to deter spam. No total cap per user. SQLite handles millions of rows fine.
Does the target URL have to be HTTPS?
Both HTTP and HTTPS are accepted. Some mobile browsers may block HTTP redirects — we recommend HTTPS regardless.