Spec & internals
UTF-8 and Unicode in QR codes: emoji, CJK and the legacy trap
QR codes carry Unicode by encoding text as UTF-8 in byte mode: emoji, CJK and accented characters all work on modern phone scanners without an ECI header. The costs: each character takes 1–4 bytes (an emoji is typically 4), and some legacy readers wrongly assume Shift-JIS and show garbled text.
How Unicode gets into a QR code
There is no "Unicode mode". Byte mode stores whatever octets you give it, so the universal recipe is: encode the string as UTF-8, store the bytes, and rely on the decoder to interpret them as UTF-8, which every current iOS and Android camera does by default. No ECI header needed in practice.
That means a QR code can carry Grüße aus Köln, 東京タワー, مرحبا, or I ♥ QR 🎉
(any Unicode text) subject only to capacity.
What Unicode costs
UTF-8 is variable-width, and QR capacity is counted in bytes, not characters:
| Characters | UTF-8 bytes each | Bits in the symbol |
|---|---|---|
| ASCII (URLs, A–Z, digits) | 1 | 8 |
| Latin accents (é, ü, ñ) | 2 | 16 |
| CJK, most scripts | 3 | 24 |
| Emoji (🎉 = U+1F389) | 4 | 32 |
A 100-character Japanese message is ~300 bytes, the size of a 300-character English one. An emoji costs four times an ASCII letter, and composed emoji (skin tones, families) chain multiple code points: 👨👩👧 is 18 bytes. Capacity ceilings are byte ceilings: 2,953 bytes at version 40-L is only ~980 CJK characters or ~730 emoji. For dense text, Kanji mode can beat UTF-8 for pure Japanese, at a compatibility price.
The legacy Shift-JIS trap
QR codes were designed at Denso Wave in 1994 for Japanese industry, and the original byte-mode assumption was JIS/Shift-JIS text. Consequences that survive today:
- Old Japanese-market readers (and some embedded decoders derived from them)
interpret unlabelled bytes as Shift-JIS. Your UTF-8
caférenders as mojibake. - Some decoders sniff and guess wrong on short, ambiguous payloads, a few bytes of accented Latin-1 can also be valid Shift-JIS, and the guess goes to the wrong one.
- The reverse trap exists too: text encoded as Shift-JIS by a Japanese generator shows garbled on a UTF-8-assuming Western app.
For URLs none of this matters: ASCII is identical in every candidate encoding, which is one more reason payloads that must work everywhere should be a plain ASCII URL with the interesting content behind it.
A real implementation bug worth knowing
Unicode handling is where QR libraries quietly go wrong. A concrete example from UseQR's
own stack: the underlying qrcode-generator library's default string handling keeps only
the low byte of each JavaScript character code: multi-byte characters are silently
mangled. UseQR pre-expands every string into its UTF-8 octets before encoding, so 東京
or an emoji arrives intact. If you use a QR library directly, test a non-ASCII payload
and decode the output before trusting it. This class of bug produces codes
that look perfect and scan to garbage.
The same caution applies to WiFi passwords and vCards, where special characters meet format-specific escaping rules on top of the encoding question.
FAQ
Can a QR code contain emoji?
Yes. Emoji are encoded as UTF-8 in byte mode (typically 4 bytes each, more for composed sequences), and modern phone scanners display them correctly. They work in text payloads; inside URLs they must additionally be percent-encoded.
Does a QR code support Chinese, Japanese and Korean text?
Yes, as UTF-8 at 3 bytes per character, readable by all current phone cameras. For pure Japanese text, kanji mode stores Shift-JIS characters in 13 bits instead of 24, but with narrower generator and reader support.
Why does my QR code show garbled characters?
Almost always an encoding mismatch: the bytes are UTF-8 but the reader assumed Shift-JIS or Latin-1, or the generator mangled multi-byte characters before encoding. Regenerate as clean UTF-8 and test on the scanners your audience actually uses.
Do special characters make a QR code bigger?
Yes. Any non-ASCII character forces byte mode and costs 2–4 bytes in UTF-8, so accented or CJK text reaches a given QR version sooner than plain ASCII. Capacity limits are counted in bytes, not characters.
Try it: free, no signup
Related
- ECI: how QR codes declare a character encoding, The Extended Channel Interpretation header tells decoders how to interpret byte mode: UTF-8 is ECI 26. Most decoders assume UTF-8 anyway; old ones choke.
- QR code data encoding modes: numeric, alphanumeric, byte, kanji, Numeric packs 3.33 bits per character, alphanumeric 5.5, byte 8, kanji 13. Mode choice is why HTTPS://USEQR.APP makes a smaller code than the lowercase URL.
- Kanji mode explained: 13 bits per character, Kanji mode packs double-byte Shift-JIS characters into 13 bits (46% denser than UTF-8 byte mode), but few generators emit it and UTF-8 rules in practice.
- How much data fits in a QR code, Theoretical ceilings are 7,089 digits, 4,296 alphanumeric characters or 2,953 bytes, but the practical answer is to keep URLs under about 50 characters.