
What is an internationalized domain name (IDN)?
An internationalized domain name (IDN) is a domain name that contains characters outside the basic English letters, digits and hyphen, such as accented letters (bücher.de), Cyrillic (пример.рф), Arabic, Chinese or Japanese script. Because DNS itself only handles plain ASCII, every IDN has a hidden ASCII form called Punycode, which always starts with xn--. Browsers and email clients convert between the two automatically, so people see bücher.de while DNS sees xn--bcher-kva.de. IDNs let people use domain names in their own language and script, at both the second level and, for many countries and brands, at the top level too.
IDNs are simple to register but have a few quirks that catch out site owners and developers alike. This article explains how IDNs work under the hood, how Punycode conversion happens, which top-level domains support them, the security problem known as homograph attacks, how to convert and validate IDNs in Python and JavaScript, and what to consider before registering one for your business.
How IDNs Work
The DNS was designed around a small character set often called LDH: letters a to z, digits 0 to 9 and the hyphen. Rather than change every DNS server in the world, the IDN standards add a conversion layer in applications.
U-Labels and A-Labels
Each part of a domain between the dots is a label. The IDN standards give the two forms of a label specific names:
| Term | Meaning | Example |
|---|---|---|
| U-label | The Unicode form people read and type | bücher |
| A-label | The ASCII-compatible form used in DNS | xn--bcher-kva |
| ACE prefix | The marker that identifies an A-label | xn-- |
When you type bücher.de into a browser, it:
- Normalises the input, for example converting upper case to lower case and composing accented characters into a single code point.
- Checks each label against the rules for permitted characters.
- Encodes any label that contains non-ASCII characters using the Punycode algorithm and adds
xn--. - Looks up the resulting ASCII name,
xn--bcher-kva.de, in DNS as normal.
DNS servers, registries and nameservers only ever deal with the A-label. The Unicode form exists in browsers, apps and on business cards.
What Punycode Actually Does
Punycode (RFC 3492) is a compact way of representing Unicode in ASCII. It writes out the plain ASCII characters of a label first, then a hyphen, then an encoded description of where the non-ASCII characters go and what they are. For bücher:
- The ASCII characters are
bcher. - The suffix
kvaencodes "insert ü at position 1". - Adding the prefix gives
xn--bcher-kva.
Labels written entirely in another script, such as пример (Russian for "example"), have no ASCII characters to keep, so the whole label is encoded: xn--e1afmkfd.
IDNA2003 vs IDNA2008
There are two generations of IDN rules, and the difference still matters.
- IDNA2003 was the original standard. It used a mapping step that, among other things, converted the German
ßtossand the Greek final sigmaςtoσ. - IDNA2008 (RFCs 5890 to 5894) replaced it with a stricter, script-aware list of permitted characters and treats
ßandςas real, distinct characters.
In practice, most browsers follow UTS #46, a Unicode compatibility layer that lets them handle both. The ß example shows why this matters: under the old rules, straße.de and strasse.de were the same domain, but under IDNA2008 they're different names that can be registered by different people. The .de registry has accepted ß registrations since 2010.
You'll see this difference in code later in this article, because Python's built-in codec still follows IDNA2003.
Where You Can Use IDNs
At the Second Level
Many generic and country-code TLDs accept IDN registrations under them, for example café.com or bücher.de. Each registry publishes an IDN table listing exactly which characters and scripts it accepts. A German registry may accept Latin letters with German, French and other European accents, while a Russian registry accepts Cyrillic. Support for a script under .com doesn't mean every registry offers the same.
Registries also have rules for variants. Some scripts contain characters that look alike or are considered equivalent, such as traditional and simplified Chinese forms. Some registries block or bundle these variants so the same person holds both.
At the Top Level
Since 2010, the root zone has included IDN TLDs:
- IDN ccTLDs, run under ICANN's Fast Track process, for countries and territories, for example
.рф(Russia,xn--p1ai),.中国(China) and.ελ(Greece). - IDN gTLDs, added through the new gTLD programme, for example
.在线("online" in Chinese) and.みんな("everyone" in Japanese).
The full list is in the IANA root zone database. A full IDN name, such as пример.рф, lets someone type a web address without switching keyboard layouts at all. For the wider picture of extension types, see gTLDs vs ccTLDs vs new TLDs.
Converting IDNs on the Command Line and in Code
Checking an IDN With dig
dig doesn't always convert Unicode input for you, depending on how it was built, so the safest approach is to query the A-label directly:
dig +short xn--bcher-kva.de A
dig +short xn--p1ai NS
c.tld-servers.ru.
b.dns.ripn.net.
a.dns.ripn.net.
d.dns.ripn.net.
The second command returns the nameservers for .рф, showing that the top-level domain is stored in DNS purely in its ASCII form. For more on querying DNS, see how to use the dig command.
You can also look up registration data for an IDN with RDAP, again using the A-label. Here xn--caf-dma.com is the A-label for café.com:
curl -sL https://rdap.org/domain/xn--caf-dma.com | jq '{ldhName, status}'
{
"ldhName": "XN--CAF-DMA.COM",
"status": [
"client transfer prohibited"
]
}
Many ccTLD registries, including several that offer IDNs, don't publish RDAP through the IANA bootstrap list, so not every IDN returns data this way. RDAP covers the protocol in more detail.
Python
Python has a built-in idna codec, but it implements IDNA2003:
print("bücher.de".encode("idna"))
print("пример.рф".encode("idna"))
print(b"xn--bcher-kva.de".decode("idna"))
print("straße.de".encode("idna"))
b'xn--bcher-kva.de'
b'xn--e1afmkfd.xn--p1ai'
bücher.de
b'strasse.de'
The last line shows the IDNA2003 mapping: ß became ss, which points at a completely different domain under modern rules. For correct IDNA2008 handling, install the third-party idna package:
pip install idna
import idna
print(idna.encode("straße.de", uts46=True))
print(idna.decode("xn--strae-oqa.de"))
try:
idna.encode("bad_label.example")
except idna.IDNAError as exc:
print("Rejected:", exc)
b'xn--strae-oqa.de'
straße.de
Rejected: Codepoint U+005F at position 4 of 'bad_label' not allowed
The uts46=True option applies the same normalisation browsers use, such as lowercasing, before encoding. Without it, input with capital letters is rejected.
JavaScript and Node.js
In Node.js, url.domainToASCII() and url.domainToUnicode() follow UTS #46 with IDNA2008 behaviour:
const url = require("node:url");
console.log(url.domainToASCII("bücher.de"));
console.log(url.domainToASCII("straße.de"));
console.log(url.domainToASCII("пример.рф"));
console.log(url.domainToUnicode("xn--r8jz45g.jp"));
xn--bcher-kva.de
xn--strae-oqa.de
xn--e1afmkfd.xn--p1ai
例え.jp
In browsers and Node.js, the URL class converts the host name automatically:
const u = new URL("https://bücher.de/katalog");
console.log(u.hostname);
console.log(u.href);
xn--bcher-kva.de
https://xn--bcher-kva.de/katalog
url.domainToASCII() returns an empty string for an invalid domain, so check for that before using the result.
Storing Domains in Your Application
If your application stores or compares domain names, for example in a list of customer domains or an allowlist:
- Store the A-label as the canonical value. It's ASCII, unambiguous and what DNS uses.
- Convert user input to the A-label before comparing, so
Bücher.DEandxn--bcher-kva.dematch. - Display the U-label to users where it's safe, so they recognise their domain.
- Use one library everywhere, since IDNA2003 and IDNA2008 tools can disagree.
IDN Homograph Attacks
The biggest risk with IDNs is that different characters can look identical. The Cyrillic а (U+0430) is visually the same as the Latin a (U+0061) in most fonts. An attacker can register a domain that looks exactly like a well-known brand:
const url = require("node:url");
const lookalike = "аpple.com"; // first letter is Cyrillic
console.log(lookalike, "->", url.domainToASCII(lookalike));
аpple.com -> xn--pple-43d.com
On screen, аpple.com is indistinguishable from the real thing, but in DNS it's a completely different domain. This is called an IDN homograph attack, and it's a form of the lookalike tricks described in what is typosquatting.
How Browsers Defend Against It
Modern browsers decide whether to show the Unicode form or the Punycode form based on a set of rules. Roughly, they show Punycode when:
- A single label mixes scripts in a suspicious way, such as Latin and Cyrillic together.
- A label is written entirely in one script but uses only characters that look like Latin letters, as in the example above.
- The label contains characters that are commonly abused, such as certain dashes or invisible characters.
So a visitor may see xn--pple-43d.com in the address bar, which is a strong warning sign. The exact rules differ between browsers and change over time, so they're a safety net rather than a guarantee.
Registries add their own protections. Most refuse labels that mix scripts, and many apply variant blocking so lookalike registrations are refused or tied to the original.
Protecting Your Own Brand
- Check whether obvious lookalikes of your domain are available, especially in Cyrillic and Greek, which share many shapes with Latin.
- Monitor new registrations that resemble your brand. Several security services include IDN variants in their alerts.
- Use email authentication so lookalike domains can't easily pass as you. See how to prevent email spoofing.
Practical Issues With IDNs
IDNs work well in modern browsers, but some parts of the internet are less friendly:
- Email addresses: A non-ASCII domain in an email address requires support for internationalised email (SMTPUTF8, also called EAI). Many large providers support it, but not every mail server, form validator or CRM does. Using the A-label, such as
info@xn--bcher-kva.de, works everywhere but looks odd. - Form validation: Many websites reject non-ASCII characters in domain or email fields.
- SSL/TLS certificates: Certificates list the A-label. Certificate authorities, including Let's Encrypt, issue them for IDNs without trouble, but you request them using the Punycode form.
- Server configuration: Web servers and DNS zone files expect the A-label. In Nginx, write
server_name xn--bcher-kva.de;, not the Unicode form. - Typing: Visitors without the right keyboard layout may struggle to type your domain.
- Displays and sharing: Some apps, social networks and messaging tools show the Punycode form, which can look suspicious to people who don't recognise it.
Here's a zone file and an Nginx block for an IDN, both using the A-label:
$ORIGIN xn--bcher-kva.de.
@ 3600 IN A 203.0.113.10
www 3600 IN CNAME xn--bcher-kva.de.
server {
listen 80;
server_name xn--bcher-kva.de www.xn--bcher-kva.de;
return 301 https://xn--bcher-kva.de$request_uri;
}
Should You Register an IDN?
An IDN makes the most sense when:
- Your audience reads a non-Latin script, and a domain in that script is easier to remember and type.
- Your brand name includes an accented letter that people naturally type, such as a German or French name.
- You want to protect your brand against lookalikes or native-script versions.
A common approach is to use an ASCII domain as the primary website and register the IDN version as well, forwarding it to the main site with a 301 redirect. That way, people who type the native spelling still reach you, while email and integrations use the ASCII domain. See what is domain forwarding for how to set that up. Search engines handle IDNs normally and index them under their Unicode or Punycode form, so an IDN isn't an SEO disadvantage in itself.
FAQ: Internationalized Domain Names
It's the prefix that marks a label as Punycode, the ASCII form of an internationalized domain name. Browsers convert it back to the original characters for display, unless they suspect a lookalike attack.
Accented letters are widely supported in registries whose IDN tables allow them. Emoji domains are not permitted under IDNA2008, so most gTLDs and many ccTLDs refuse them, although a few ccTLD registries still accept them.
Partly. Sending mail to an address with a non-ASCII domain requires internationalised email support on both ends. Using the Punycode form of the domain in the address works everywhere but isn't user friendly.
Browsers display Punycode when a domain could be confused with another one, for example when it mixes scripts or uses characters that look like Latin letters. It's a protection against homograph phishing.
No. Search engines index IDNs like any other domain and can show them in their native script. The main challenges are practical ones, such as typing, sharing and email compatibility.
Always the Punycode form, such as xn--bcher-kva.de. DNS, web servers and certificate requests work with the ASCII form, and browsers handle the conversion for visitors.
Conclusion
An internationalized domain name lets you use letters and scripts beyond basic ASCII, from ü and ß to Cyrillic, Arabic and Chinese characters. Behind the scenes, every IDN is converted to a Punycode A-label starting with xn--, which is the form DNS, registries, certificates and servers actually use. Browsers handle the conversion invisibly, and modern rules based on IDNA2008 and UTS #46 decide which characters are allowed.
If you work with IDNs, store and configure the A-label, convert user input with a library that follows current standards, and be aware of the gaps in email and form support. Keep homograph attacks in mind too: check for lookalikes of your own brand, and treat an unexpected xn-- in the address bar as a warning sign. Used well, an IDN can make your domain far more natural for the people you're trying to reach.


