Plain text QR code — when the payload is the text itself

A plain text QR code stores the message directly in the pixels, with no redirect, no internet, and no scan tracking. Here is when and how to use a plain text QR code.

Jun 2, 2026 15 min read Linked.Codes
Plain text QR code — when the payload is the text itself

A plain text QR code carries the message itself, not a link to the message. The bytes a scanner reads off the modules are the text. No redirect server, no internet round-trip, no analytics row written somewhere — the phone decodes the pixels, shows the string, and offers to copy it or share it. That sounds like a small distinction until you start counting the things it changes: offline workflows that work, passwords that don't leak through redirect logs, classroom answer keys that survive a wifi outage, activation strings that print on a card and never phone home.

Most QR posts assume the payload is a URL because most QR codes in the wild are URL-carrying. The format doesn't care. The 1994 Denso Wave spec defined the QR code as a generic data container — store anything that fits in 2,953 bytes and let the scanner-side software figure out what to do with it. Text was always one of the supported payloads. It's the use cases around text that have stayed quiet, partly because the SaaS economics push everyone toward dynamic redirects, partly because plain text lacks the metrics that make a marketing dashboard look busy.

This post is the practical guide to the plain text variant. What scanners do with non-URL text, how much text fits in a code, the privacy posture, the workflow patterns that actually use it, and the small set of decisions that decide whether a plain text QR is the right call or whether you should reach for a dynamic redirect instead.

The payload is the text, and that's the whole trick

When you encode Activation code: 7B9A-2X4F-PD8K directly into a QR, the modules in the printed pattern are the bytes of that exact string. A scanner reads the pixels, recovers the bytes, decodes them as UTF-8, and gets back the original message. The scanner has no idea those bytes "mean" an activation code. It just shows the user the text and offers to copy it, share it, or search the web for it. That handoff is what makes the plain text mode genuinely offline — the phone never has to reach a server to deliver the payload.

Compare that to a dynamic QR code. There, the modules encode a short URL like lnks.work/q/abc123. The scanner reads the URL, the phone opens the link, the request hits a redirect server, the server looks up abc123, finds the current destination, and sends the user there. Five round-trips, three trust boundaries, one third-party platform that has to be alive for the link to resolve. None of that exists when the QR is plain text. The full mechanic on the redirect side is in what is a dynamic QR code — useful contrast for understanding what plain text gives up and what it earns.

Dynamic, static, and plain text QR — where the payload lives in each Three QR types, three places the data actually lives DYNAMIC lnks.work/q/abc payload = short URL destination on a server requires internet STATIC URL example.com/page payload = full URL destination = the URL requires internet PLAIN TEXT Activation: 7B9A-2X4F payload = the message destination = the message works offline
Three QR types arranged by where the payload lives. Dynamic depends on a server, static depends on a public URL, plain text depends on nothing — the message is in the modules.

The honest trade-off: plain text gives up edit-after-print and analytics in exchange for offline operation, zero scan tracking, and complete platform independence. For the ~80% of business QR use cases where edits and analytics matter, dynamic is the right call. For the 20% where the payload genuinely is the message — credentials, codes, notes, classroom answers, in-product strings — plain text is the cleaner answer.

How much text actually fits

This is the number people get wrong by an order of magnitude in both directions. The QR code spec defines 40 versions, from 21x21 modules (version 1) up to 177x177 modules (version 40). Each version has a fixed capacity that varies by encoding mode and error-correction level. The four modes — numeric (digits only), alphanumeric (uppercase + a handful of symbols), byte (any UTF-8 text), and kanji (Japanese double-byte) — pack data at different densities because they use different bits per character.

Numeric vs alphanumeric vs byte vs kanji — capacity comparison at version 40 ECC level L Capacity by mode at version 40, error correction L Numeric 0-9 only 7,089 digits Alphanumeric A-Z 0-9 + symbols 4,296 chars Byte (UTF-8) any 8-bit text 2,953 bytes Kanji Shift JIS 1,817 chars All caps drop ~50% at ECC level H (30% damage tolerance). Most real-world plain text codes land in byte mode at level M or Q.
Maximum theoretical capacity in each mode. Numeric is densest because digits pack at 3.33 bits each; byte mode is the practical default for mixed-case text and lands around 2,953 bytes before error correction eats into it.

The widely-quoted "3KB" headline is the version-40, level-L, byte-mode number — the theoretical ceiling for arbitrary UTF-8 text. The "1,800 alphanumeric" headline is the version-40, level-H, alphanumeric-mode number — the ceiling for uppercase-and-digits payloads when you want maximum damage tolerance. Both are real. Both are also irrelevant to most practical plain text QR codes, which run far smaller.

The numbers you actually care about for plain text:

  • A 20-character message (a short code, a name, a short note) fits in version 1 or 2 at level H. Tiny on the page, scans from a phone at any reasonable size.
  • A 100-character message (a sentence or two, a short address, a password phrase) needs version 5 or 6 at level Q. Still print-friendly, still scans from arm's length.
  • A 500-character message (a paragraph, a multi-line activation block, a short poem) lands in version 15 to 20 at level M. The code gets visibly dense — print bigger or accept that scan distance drops.
  • A 1,500-character message (an FAQ snippet, a wifi config block, a short instruction set) is version 27 to 30 at level M. The modules get tight enough that printing under 5cm becomes unreliable.

Past ~2,000 alphanumeric or ~1,500 bytes of mixed text, the code stops being a QR you can print on a business card and starts being a QR that needs poster-sized real estate to scan from a phone. That's the practical ceiling for "plain text on something you can hold in your hand."

The version a generator picks is automatic — you give it the text, it picks the smallest version that fits at your chosen error-correction level. The mode is also automatic in most generators; the encoder picks alphanumeric if your text fits its limited character set, byte otherwise. The decision you actually make is error correction, which trades capacity for damage tolerance. The full trade-off is in QR error correction levels — short version, level M (15% recovery) is the right default for plain text, level Q (25%) if the code might get smudged or printed on uneven stock.

What scanners do with non-URL text

This is the part most people don't know until they try it. Every modern phone scanner — iOS Camera since iOS 11, Google Lens on Android, every dedicated QR app — has logic that inspects the decoded string and decides what to offer.

If the string starts with http:// or https://, the scanner offers to open the URL.

If the string matches a known URI scheme — mailto:, tel:, sms:, geo:, WIFI:, MATMSG:, BEGIN:VCARD, BEGIN:VEVENT — the scanner offers a specific action (compose an email, dial a number, join a network, save a contact, add to calendar).

If the string matches none of those, the scanner falls back to plain text mode. It shows the decoded string on screen, usually with three buttons: copy, share, search the web for. Some scanners also offer a fourth button to open the string as a URL if it looks vaguely URL-shaped (this is what causes the occasional phishing-adjacent edge case — a string like microsoft-support.help gets offered as a clickable link even though it has no scheme).

Phone screen behaviour when the QR payload is plain text What a phone shows when the QR carries plain text QR DETECTED Activation code: 7B9A-2X4F-PD8K Copy Share Search No URL — no link prompt, no network call Decoded bytes → scanner reads the modules, recognises no URI scheme, falls back to text display User options → copy to clipboard, share via system sheet, or paste into the app of choice
iOS Camera and Google Lens both fall back to the same pattern when the payload has no URI scheme — display the text, offer copy and share. No network call, no link prompt, no analytics row written anywhere.

The takeaway: plain text doesn't auto-open anything. The user reads the string, copies it, pastes it where they need it. That's a feature, not a friction — for credentials, activation strings, and any payload where you specifically don't want a phone to automatically follow a link, the fall-back-to-text-display behaviour is exactly the right interaction model.

Where plain text earns its keep

The use cases that actually benefit from plain text QR over a dynamic redirect are narrower than the QR-everywhere marketing crowd would have you believe — but where they fit, nothing else does the job.

Activation codes and license keys. Software install codes printed on a card inside a box. The QR carries the literal string the user types into the app. No network round-trip — the activation happens in the software, not in the scan. The plain text variant survives the customer's wifi being down, the platform being offline, and the company being acquired and pivoted three years later. The card and the code keep working as long as the printed pixels stay readable.

Classroom answer keys. Teacher prints the answer key as a plain text QR on a worksheet. Students scan after they finish, the phone shows the answers, and the school's wifi has nothing to do with it. No tracking, no scan logs, no chance the answers are exposed by a platform breach because the answers were never on a platform.

Password sharing on labels. Wifi passwords get their own format (WIFI:S:...;T:WPA;P:...;;) that triggers a one-tap join. But for non-wifi passwords — a guest network credential on a printed sheet, a vault recovery passphrase printed on a backup card, a temporary access code on a meeting room door — plain text is the right fit. The scanner shows the string, the user copies it, no third party logs it.

Offline product activation. Industrial equipment, medical devices, kiosks — anywhere the device that needs to read the code might not have an internet connection. A plain text QR on a service sticker can carry a serial number, a configuration string, or a diagnostic code that the on-device scanner reads and processes without ever calling out.

Hidden messages and creative payloads. Geocaching coordinates printed on a marker. A short story chapter printed on a card. A poem inside a museum exhibit. Anywhere the QR is the medium and the message is the point, plain text gives you a payload that doesn't depend on a server staying up.

In-product activation strings on physical media. Books with companion QR codes that unlock content via a code (rather than a redirect). Board games with cards that carry plain text codes for in-app verification. The card and the QR work whether the publisher is alive or dead.

What plain text is not the right answer for: marketing landing pages, anything you want analytics on, anything where the destination might change, anything where the audience expects the QR to "just open something." For all of those, dynamic redirects are the right default, and the whole QR codes platform docs page walks through the redirect-side options.

A plain text QR code is the smallest possible attack surface for a QR you put on a printed surface — no destination to compromise, no platform to outlast, no scan log to leak.

The privacy posture, in plain language

This is the part most posts about QR codes don't make explicit. Every dynamic QR code involves at least one redirect server, and every redirect generates a log line — timestamp, source IP, user agent, often a referrer. Most platforms aggregate that into analytics dashboards their customers love. None of that exists with a plain text QR.

When a user scans a plain text QR:

  • No request leaves the phone. The decoder is local. The bytes are extracted from the pixels by software running on the device.
  • No server is consulted. There's no URL to follow, so no DNS lookup, no TLS handshake, no redirect lookup, no analytics row.
  • No third party knows the scan happened. Not the QR platform, not the operator, not anyone running ads on the destination page (because there is no destination page).
  • The phone may or may not log the scan locally. iOS Camera does not. Most third-party QR scanner apps do, in a history list scoped to the app — that's a user-side log, not a platform-side one.

For activation codes, passwords, classroom answers, and any payload where the user reasonably expects the scan to be private, plain text is the only QR variant that delivers that property. The redirect-based alternatives all involve a third party seeing the scan happen — fine for marketing, wrong for credentials.

The opposite side of the same trade-off: you also can't tell if a plain text QR is being scanned. No scan counts, no engagement metrics, no proof the campaign worked. For a marketing surface that matters. For an activation code on a license card, it doesn't.

Try the capacity calculator

Pick a text length, a mode, and an error-correction level. The calculator tells you the smallest QR version that fits, the resulting module count, and whether the code is print-friendly at typical sizes. State persists in your browser so you can come back and tune.

Plain text QR capacity calculator

Type your text length, pick the mode and error correction. The calculator returns the smallest version, the module count per side, and whether the code is print-friendly at typical sizes.

Minimum version
v2
Modules per side
25 x 25
Fits in version 2. Prints cleanly at 2 cm square or larger.

The version-jumps are non-linear. Doubling the text length usually moves you up two or three versions, not one. The print-size threshold is the practical ceiling — once you cross into version 25 or higher, the QR stops being a thing you scan at arm's length and becomes a thing you have to walk up to.

Plain text vs URL — for tracking specifically

The privacy distinction deserves its own beat. With a URL-carrying QR (static or dynamic), every scan that follows the link generates at least three log entries somewhere:

  1. The DNS resolver log — a record that someone looked up the QR's domain.
  2. The redirect server log (for dynamic) — a record that the slug was resolved.
  3. The destination server log — a record that the destination URL was fetched.

If the redirect host is a third-party platform, that platform owns log #2 — they see every scan, when, from what IP, on what device. That's what powers QR analytics dashboards. It's also the trail that exists if anyone subpoenas the platform or breaches their database. For most marketing payloads that's fine. For credentials and codes, it's a privacy leak that didn't have to happen.

With a plain text QR, none of those logs exist. The phone reads the modules, decodes the bytes, displays the text. No request goes out. No third party knows the scan happened. The only entity that knows the user scanned the code is the user. That's the privacy posture, and it's the property that makes plain text the right call for credentials, classroom answers, and any payload where the existence of the scan should be private.

When plain text is the wrong call

Three cases where plain text is genuinely the wrong answer and dynamic redirects earn their cost:

The destination might change. Print a marketing QR with a URL baked in, and the day the URL changes is the day every copy of the QR is dead. A dynamic redirect survives the URL change because you update the destination on the server side. The argument for why dynamic types are the default on Linked.Codes covers the reasoning in full.

You need analytics. Plain text QRs are uncountable. If proving the campaign worked is part of your job, you need redirect-based scan tracking. The marketing case for it is straightforward; the privacy trade-off is the price.

The payload is too long. Past ~1,500 bytes of mixed text or ~2,000 alphanumeric characters, the QR's print size becomes prohibitive. A 50-character short URL pointing at a long page is the cleaner answer. The QR code minimum print size math covers the version-to-physical-size relationship.

For everything outside those three, plain text is at least worth considering, and for the credential and code use cases it's the only correct answer.

Try the plain text QR generator

Build a plain text QR right now — type the message, pick the error correction, see the modules at print size. No signup, the QR you generate carries the literal text and works offline forever.

Open the text QR code generator

The generator picks the version automatically based on your text length and the error-correction level you choose. Download the PNG, print it on whatever surface fits the use case, and the message lives in the pixels.

FAQ

What does my scanner actually do when the QR contains non-URL text?

It decodes the bytes, recognises that the string has no URI scheme (no http://, no mailto:, no tel:, etc.), and falls back to text display. iOS Camera and Google Lens both show the text on screen with Copy and Share buttons. No link prompt, no network call. The user reads or copies the string and decides what to do with it.

Can I encode a password into a QR safely?

Yes, but understand the trade-off. A plain text password QR keeps the password off any redirect server's logs — that's the privacy win. But anyone who can photograph the printed code can decode it, so physical security matters. Don't print sensitive passwords on surfaces visible to bystanders. For high-value secrets, a one-time-use code is safer than a permanent one.

How much text actually fits in a QR code?

Up to ~2,953 bytes for UTF-8 text or ~4,296 alphanumeric characters at version 40 with the lowest error correction. Practical print-friendly ceiling is closer to ~500 bytes (version 15-20) for a code that scans cleanly at business-card size. The capacity calculator above shows the exact version for any combination.

Can the text in a plain text QR be edited later?

No. The text is baked into the printed pixels. Change the text and you reprint the QR. That's the fundamental trade-off — plain text is the offline, server-free option, and the cost is permanence. If edit-after-print matters, that's what dynamic QR codes are for.

How is a plain text QR different from a URL QR for tracking?

A URL QR (static or dynamic) generates server-side logs every time someone scans it — the redirect platform, the destination server, sometimes the DNS resolver. A plain text QR generates no remote logs at all. The phone decodes the bytes locally and never reaches out. For analytics that's a loss; for privacy that's the whole point.

Will every phone scan a plain text QR?

Yes. Every QR scanner — native iOS Camera since iOS 11, Google Lens, every third-party app — supports plain text payloads because the QR specification has always supported them. The behaviour is consistent across the major platforms.

Are plain text QR codes safer than URL QR codes?

For the user, yes — there's no URL to follow, so no phishing risk and no malicious redirect. The string the scanner shows is the string. The user can read it before acting on it, which is more friction than a one-tap URL prompt and substantially safer. The wider QR phishing risks and how to recognise them covers the URL-QR side of the same question.

Sourcesshow citations

Try it on your own domain

Branded short links and dynamic QR codes, on your subdomain or your own domain. One-time purchase, no per-click fees.