Skip to content
UseQR
ESC

Jump to

MOVEOPEN50 places

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.

View as MarkdownPaste this page into any AI assistant. It is plain, portable Markdown.

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