Glossary
Plain English
Cross-linked to tools

Punycode

Also known as: RFC 3492, xn--, ACE prefix, ASCII Compatible Encoding

Punycode is the encoding defined by RFC 3492 that represents a Unicode string using only the letters, digits and hyphen that DNS allows, producing the xn-- labels that carry internationalised domain names.

Overview

DNS labels are restricted to letters, digits and the hyphen — a rule from the 1980s that predates Unicode and cannot be changed without breaking every resolver in existence. Punycode is the workaround: it rewrites a Unicode label into that restricted alphabet, and prefixing the result with xn-- marks it as encoded. So bücher becomes xn--bcher-kva, and every resolver in the path handles plain ASCII while the browser displays the original.

The encoding is an instance of Bootstring, and it is cleverer than escaping each character. The ASCII characters in the label are copied through unchanged and a hyphen separates them from what follows, which is why xn--bcher-kva still visibly contains 'bcher'. The non-ASCII characters are then appended not as code points but as a compressed sequence of insertion instructions — each one saying which code point to insert and where — with an adaptive bias that shrinks the encoding when the characters come from the same region of Unicode. That is why a Chinese label encodes far more compactly than a random mixture would.

Punycode alone is not enough to turn a domain into its xn-- form, and this is where implementations go wrong. UTS #46 requires a preprocessing pass first: case folding, mapping compatibility characters to their plain equivalents, and normalising to NFC. Skipping it produces plausible but wrong results — a decomposed 'café' encodes to xn--cafe-yvc instead of xn--caf-dma, a different domain — so a converter that calls a bare Punycode library disagrees with the address bar.

The encoding is also why homograph attacks are visible at all. Because Cyrillic а and Latin a are different code points, аpple.com encodes to xn--pple-43d.com, and browsers exploit that by displaying the xn-- form rather than the Unicode one whenever a name mixes scripts in a suspicious way. The ugly label is the security feature.

Common questions about Punycode

What does xn-- mean at the start of a domain?
It is the ACE prefix, and it marks the label as Punycode-encoded rather than literal. A resolver sees xn--bcher-kva as an ordinary ASCII label; a browser recognises the prefix, decodes the rest, and displays bücher instead. Seeing xn-- in your address bar for a name you expected to read normally is worth a second look, because browsers fall back to showing it when a name mixes scripts.
Why does xn--bcher-kva still contain readable letters?
Because Punycode copies the ASCII characters through unchanged and separates them from the encoded part with a hyphen. 'bücher' has the ASCII letters b, c, h, e, r, which survive as 'bcher', and 'kva' encodes where the ü goes and which character it is. This is what makes Punycode more compact than escaping every character, and it is why an encoded label often looks like a typo of the original.
Is Punycode the same as IDN?
No. An internationalised domain name is the concept; Punycode is one step in representing it. Converting a name to its ASCII form is a full pipeline defined by UTS #46 — map the characters, normalise to NFC, split into labels, validate each one, then Punycode-encode the ones that need it. Treating Punycode as the whole job is the most common source of converters that disagree with browsers.
Can Punycode be decoded back to the original exactly?
The Punycode step is exactly reversible, but the IDNA pipeline around it is not. The mapping pass is lossy on purpose: uppercase folds to lowercase, fullwidth characters map to plain ASCII, and ignored characters like a soft hyphen are discarded. So xn--bcher-kva decodes to bücher precisely, but you cannot recover whether the person originally typed Bücher or BÜCHER.
Why do browsers sometimes show xn-- instead of the real name?
As an anti-spoofing measure. Each browser applies rules about which scripts may appear together in a label and whether the characters suit the top-level domain, and when a name fails them the browser shows the raw xn-- form. Cyrillic а is indistinguishable from Latin a in most fonts, so displaying xn--pple-43d.com rather than аpple.com is the only reliable way to tell you that this is not the domain you think it is.

Tools that work with Punycode

Punycode / IDN Converter

Convert between Unicode domain names and xn-- Punycode, with full UTS #46 and homograph checks.

URL Parser

Break any URL into its protocol, host, path and query parameters.

URL Encoder / Decoder

Percent-encode and decode URL components instantly.

External references