Punycode Encoder / Decoder guide Convert international domain names safely

Punycode encoder — Chunky Munster

Punycode is the ASCII-safe format DNS uses for internationalized domain names, and a Punycode encoder turns human-readable Unicode labels into the xn-- form servers can store. If you need to check a certificate name, compare a log entry, or paste a domain into a config file, use try our free punycode encoder-decoder and avoid the usual Unicode gremlins.

The important part is simple: browsers can display the pretty version, but infrastructure often needs the encoded version. That split is where most confusion starts, especially when a domain looks “wrong” in DNS tools even though it is technically correct.

What Punycode actually does

DNS labels were built around ASCII. That means old systems, certificate tooling, and a lot of lower-level plumbing still expect plain letters, numbers, and hyphens.

Punycode solves that by encoding Unicode labels into an ASCII-compatible string. It does not invent a new name; it just serializes the same name safely for systems that cannot carry raw Unicode.

The encoded label usually starts with xn--. For example, a domain like münich.example becomes an ASCII label such as xn--mnich-kva.example underneath the display layer.

That distinction matters when you are debugging mismatches. A browser may show one form, while an SSL certificate, DNS zone file, or reverse proxy rule is comparing the other form byte-for-byte.

When you need the encoded form

You usually want Punycode any time a system is strict about ASCII. That includes DNS zone files, certificate SAN entries, CDN rules, mail routing, and scripts that compare hostnames directly.

A few common cases:

If your code uses the browser-facing Unicode form in one place and the encoded form in another, you will think the domain is broken when it is really just represented in two different ways.

That is why tooling matters. A quick encode/decode pass is often faster than staring at a config file and pretending the glyphs will explain themselves.

How browsers, DNS, and certificates split the job

Modern browsers usually accept Unicode in the address bar, but they still convert the host portion to ASCII for network requests. DNS only sees the encoded label. That is the part that gets queried, resolved, and compared downstream.

Certificates are another place where the difference can sting. If a certificate is issued for the Punycode form, a naive string compare against the Unicode display name may report a mismatch even though the browser resolves the same destination.

It is also worth remembering that only the hostname label is encoded. Paths, query strings, and fragments are separate parts of a URL and follow different rules. If you need a broader URL breakdown, our guide on what happens when you type a URL into your browser is the cleaner mental model.

Rule of thumb: Unicode is for humans, Punycode is for systems that demand ASCII.

Encoding and decoding without wrecking the label

Punycode encoding is reversible. That is the whole point. If you encode a label correctly, you should be able to decode it back to the same Unicode text.

What you should not do is hand-edit the output. The xn-- prefix and the encoded tail are not meant to be guessed, shortened, or rewritten by eye. One stray character and you are in phantom-domain territory.

In code, libraries typically handle this for you. In Node.js, for example, the built-in URL machinery knows how to work with IDNs:

const url = new URL('https://münich.example/path');
console.log(url.hostname);
// xn--mnich-kva.example

console.log(url.href);
// https://xn--mnich-kva.example/path

That is useful, but it also hides the conversion. When debugging, it helps to inspect both the display form and the ASCII form so you know which layer is actually failing.

Security and confusion points developers run into

Internationalized domains are useful, but they also open the door to lookalike attacks. Different Unicode characters can render similarly in some fonts, which means a domain can look legitimate while spelling something else entirely.

That is not a Punycode bug. It is a human-factors problem wrapped around Unicode. The encoding just preserves the label; it does not make a deceptive name safer.

So if you are building validation, keep a few checks in mind:

  1. compare hostnames in their normalized ASCII/Punycode form when the backend expects ASCII
  2. avoid displaying raw encoded labels to users unless they need the technical detail
  3. treat mixed-script domains with caution in admin tools and security-sensitive flows
  4. log both forms when you are investigating certificate or DNS failures

If you only ever compare the pretty Unicode string, subtle mismatches can slip through. If you only ever show the encoded form, users will hate you quietly and move on.

A Worked Example

Let us take a concrete example and move it from display form to DNS-safe form. Say you need to register or verify the hostname münich.example.

Here is what the transformation looks like:

Input (Unicode):  münich.example
Output (ASCII):   xn--mnich-kva.example

In a DNS zone file or a certificate request, the ASCII version is the one that matters. In a browser address bar or user-facing UI, the Unicode version may be the one you want to show.

If you are debugging a request, check the exact hostname the application uses, not the pretty string printed in your UI component. That one detail is often the difference between “certificate mismatch” and “everything is fine, stop looking at the wrong layer.”

Here is a slightly more realistic workflow:

1. User enters:      café.example
2. App normalizes:   café.example
3. DNS lookup uses:  xn--caf-dma.example
4. TLS cert checks:  xn--caf-dma.example
5. Logs may show:    café.example or xn--caf-dma.example depending on the stack

The key is consistency. Once you know which representation a system expects, you can convert before comparison and avoid false negatives.

Practical workflow for day-to-day debugging

When a domain containing non-ASCII characters misbehaves, move through the problem in a fixed order. First check the Unicode label the user sees. Then check the Punycode form the network stack uses. Finally verify the exact hostname stored in DNS or certificates.

A fast workflow usually looks like this:

This is boring in the best way. Boring means repeatable, and repeatable means fewer production surprises at 2 a.m.

Frequently Asked Questions

What is Punycode in simple terms?

Punycode is a way to turn Unicode domain labels into ASCII so old and strict systems can handle them. It is commonly used for internationalized domain names and usually shows up with an xn-- prefix. The readable domain and the encoded domain are the same name in different formats.

Why does a domain start with xn--?

xn-- is the marker used for Punycode-encoded IDN labels. It tells DNS-aware software that the rest of the string is encoded Unicode, not a normal ASCII hostname. If you see that prefix, you are looking at the transport-safe version of the name.

Do I need Punycode for every URL?

No. You only need it for hostname labels that contain non-ASCII characters. Paths, query strings, and fragments use different encoding rules, so a full URL may need multiple kinds of escaping depending on where the special characters appear.

Can browsers understand Unicode domains without manual encoding?

Usually, yes. Modern browsers convert internationalized hostnames to the ASCII form before making the network request. But if you are configuring DNS, certificates, proxies, or scripts, you often still need the explicit Punycode version.

The Bottom Line

Punycode is not exotic once you separate display from transport. Unicode is the human-friendly version, and the encoded ASCII form is what DNS and other infrastructure often need to keep things working across the boring old internet machinery.

If you are troubleshooting hostname mismatches, certificate issues, or a DNS record that looks suspicious, encode the label first and compare the exact ASCII output. Then decode it back if you need to confirm the readable name. When you want to do that fast, use the Punycode encoder-decoder tool and keep the guesswork out of it.

That small habit saves time, especially when the problem is not the domain itself, but the representation you are looking at.

// try the tool
try our free punycode encoder-decoder →
// related reading
← all posts