Guide · Node.js · SDK · REST API

Domain Validation in Node.js — IDN, DNS Checks & TLD Parsing

A domain that looks valid syntactically may not exist in DNS. An Internationalized Domain Name may trip up your regex. New gTLDs appear every year. Here's how to validate domains properly — format, structure, and DNS — in a single API call.

1. Why domain validation is harder than it looks

A domain name is more than a string that matches a pattern. It lives in a layered system of registrars, DNS servers, and internationalisation standards. Checking format alone misses most of the real-world complexity.

1

Internationalized Domain Names (IDN)

Domains can contain non-ASCII characters like "münchen.de" or "例え.日本". Under the hood they use punycode (xn--), but users type Unicode. Your validator must handle both representations.

2

TLD proliferation

There are now over 1,500 valid TLDs — from .com and .org to .photography, .xn--vermgensberatung-pwb, and .localhost. Hardcoding a list is a losing battle.

3

DNS vs format validity

A domain can be syntactically perfect yet point to nothing. "this-domain-does-not-exist-xyz.com" passes every regex but has no DNS records. Only a live DNS lookup confirms the domain is actually in use.

A simple regex can tell you whether a string looks like a domain — but it cannot tell you whether it actually resolves, what its TLD category is, or whether it uses internationalised characters that need special handling.


2. Common domain validation mistakes

Most domain validation code falls into one or more of these traps.

// Common but broken domain validation
const DOMAIN_REGEX = /^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

// Problems:
// 1. Rejects valid IDN domains like "münchen.de" or "例え.日本"
// 2. Hardcodes TLD as 2+ ASCII letters — misses numeric and long TLDs
// 3. Allows consecutive dots, leading hyphens, and other invalid syntax
// 4. No DNS check — "fake-domain-xyz.com" passes
// 5. No structure parsing — you don't know the TLD, SLD, or subdomain parts
!

Regex that rejects IDN domains

Patterns that only allow [a-zA-Z0-9] will reject millions of valid internationalised domain names used across Asia, Europe, and the Middle East.

!

Hardcoded TLD lists

New gTLDs are added regularly by ICANN. A static list in your codebase will become outdated within months and silently reject valid domains.

!

No DNS verification

Format validation alone cannot distinguish a registered, resolving domain from a syntactically correct but non-existent one.

!

Ignoring punycode

IDN domains have two representations: the Unicode label users see and the ACE (punycode) label used in DNS. Validators must normalise between the two.


3. The right solution

The IsValid Domain API handles format validation, IDN normalisation, TLD/SLD parsing, and live DNS verification in a single request. Pass any domain — Unicode or punycode — and get a complete breakdown.

Format & syntax validation

Validates label lengths, allowed characters, and overall domain structure per RFC 5891/5892

IDN & punycode support

Accepts Unicode domains and returns normalised form plus IDN detection flag

TLD & SLD parsing

Extracts the top-level domain and second-level domain from any valid domain

Live DNS verification

Checks for A and AAAA records to confirm the domain actually resolves

<50ms
Response time
typical latency
1,500+
TLDs supported
all IANA TLDs
100/day
Free tier
no credit card

Full parameter reference and response schema: Domain Validation API docs →


4. Node.js code example

Using the IsValid SDK or the native fetch API.

import { createClient } from '@isvalid-dev/sdk';

const iv = createClient({ apiKey: process.env.ISVALID_API_KEY });

const result = await iv.domain('example.com');
console.log(result.valid);    // true
console.log(result.domain);   // 'example.com'
console.log(result.tld);      // 'com'
console.log(result.sld);      // 'example'
console.log(result.isIDN);    // false
console.log(result.dnsValid); // true
console.log(result.hasA);     // true
console.log(result.hasAAAA);  // false

In a registration form handler — validate the domain before accepting user input:

// routes/register.js (Express)
app.post('/register', async (req, res) => {
  const { website } = req.body;

  // Extract domain from URL if the user pasted a full URL
  let domain = website;
  try {
    const url = new URL(website.startsWith('http') ? website : `https://${website}`);
    domain = url.hostname;
  } catch {
    // Not a URL — treat as bare domain
  }

  let check;
  try {
    check = await validateDomain(domain);
  } catch {
    return res.status(502).json({ error: 'Domain validation service unavailable' });
  }

  if (!check.valid) {
    return res.status(400).json({
      error: `"${domain}" is not a valid domain name.`,
    });
  }

  if (!check.dnsValid) {
    return res.status(400).json({
      error: `"${domain}" does not resolve in DNS. Please check for typos.`,
    });
  }

  // Proceed with registration
  await createUser({ ...req.body, domain: check.domain });
  res.json({ success: true });
});
The domain field in the response returns the normalised form of the domain. Use it for storage and comparison instead of the raw user input to avoid duplicates caused by casing or Unicode variations.

5. cURL example

Standard domain:

curl -G -H "Authorization: Bearer YOUR_API_KEY" \
  --data-urlencode "value=example.com" \
  "https://api.isvalid.dev/v0/domain"

Internationalized domain name:

curl -G -H "Authorization: Bearer YOUR_API_KEY" \
  --data-urlencode "value=münchen.de" \
  "https://api.isvalid.dev/v0/domain"

Invalid domain:

curl -G -H "Authorization: Bearer YOUR_API_KEY" \
  --data-urlencode "value=not a domain" \
  "https://api.isvalid.dev/v0/domain"

6. Understanding the response

Valid domain with DNS records:

{
  "valid": true,
  "domain": "example.com",
  "tld": "com",
  "sld": "example",
  "isIDN": false,
  "dnsValid": true,
  "hasA": true,
  "hasAAAA": false
}

IDN domain:

{
  "valid": true,
  "domain": "münchen.de",
  "tld": "de",
  "sld": "münchen",
  "isIDN": true,
  "dnsValid": true,
  "hasA": true,
  "hasAAAA": true
}

Invalid domain:

{
  "valid": false,
  "domain": "not a domain",
  "tld": null,
  "sld": null,
  "isIDN": false,
  "dnsValid": false,
  "hasA": false,
  "hasAAAA": false
}
FieldTypeDescription
validbooleanWhether the domain is syntactically valid
domainstringNormalised form of the domain
tldstringTop-level domain (e.g., "com", "de", "photography")
sldstring | nullSecond-level domain (e.g., "example" in "example.com")
isIDNbooleanWhether the domain is an Internationalized Domain Name containing non-ASCII characters
dnsValidbooleanWhether DNS A or AAAA records exist for the domain
hasAbooleanWhether the domain has at least one IPv4 (A) record
hasAAAAbooleanWhether the domain has at least one IPv6 (AAAA) record

7. Edge cases

Internationalized Domain Names (IDN)

IDN domains use Unicode characters — for example, "münchen.de" or "例え.jp". In DNS they are represented as punycode (e.g., "xn--mnchen-3ya.de"). The API accepts both forms and returns the normalised Unicode representation. The isIDN flag tells you whether special handling is needed.

const result = await iv.domain('münchen.de');
console.log(result.isIDN);   // true
console.log(result.domain);  // 'münchen.de' (normalised Unicode)
console.log(result.tld);     // 'de'

New gTLDs

ICANN has delegated over 1,500 generic TLDs beyond the classic .com, .net, and .org. Domains like "my.photography", "startup.io", and "company.technology" are all valid. The API maintains an up-to-date TLD registry so you never reject a legitimate new extension.

Subdomains

A domain like "blog.example.com" is a subdomain of "example.com". The API validates the full domain including subdomains and correctly parses the TLD and SLD from the effective registrable domain. If your use case requires only the root domain, strip subdomains before calling the API.

.localhost and reserved TLDs

Reserved TLDs like .localhost, .test, .example, and .invalid are defined in RFC 6761. These domains are syntactically valid but will never resolve in public DNS. The API will report dnsValid: false for these, allowing you to detect development or placeholder domains that should not be used in production.


Summary

Do not rely on regex alone — it misses IDN domains and cannot verify DNS resolution
Do not hardcode a TLD list — ICANN adds new gTLDs regularly and your list will go stale
Use the dnsValid flag to confirm a domain actually resolves before trusting it
Store the normalised domain from the response to avoid Unicode/casing duplicates
Check the isIDN flag when you need to apply special handling for internationalised domains
Use the TLD and SLD fields to categorise or filter domains by extension

See also

Validate domains instantly

Free tier includes 100 API calls per day. No credit card required. Format validation, IDN support, TLD parsing, and live DNS checks in a single call.