Last updated: 2026-07-05
A comprehensive, battle-tested WHOIS parser with support for 169 country-code TLDs (ccTLDs) and 1,260+ TLDs total. Built for DomainDetails.com by Simple Bytes LLC.
This repository includes whois_dict.json with WHOIS servers for 1,260+ TLDs (updated from IANA Root Zone Database).
This parser handles the messy reality of WHOIS data across different country registries. Unlike simple regex-based parsers, it handles:
- Multiple date formats - from
2005/05/30(Japan) to2007. 03. 02.(South Korea) to natural language dates - International field names - including Japanese (็ป้ฒๅนดๆๆฅ), Korean, and other non-English formats
- Various nameserver formats - square brackets, multi-line sections, colon-separated with IPs
- Slow WHOIS servers - with configurable 30-second timeouts
- Fallback parsing - when domain names aren't explicitly listed in responses
All fields parsed: domain, dates, nameservers, registrar, status โ Ready for production use
.ac .af .ag .bh .bi .bj .ci .cl .co .dm .do .ge .gg .gi .gl .hr .hu .ie .io .it .je .jp .kr .kz .la .ma .me .mk .mn .mx .my .nu .nz .pk .pt .ru .sc .se .sg .sh .sk .so .st .su .sx .sy .tc .td .tl .us .ve .ws .ไฟกๆฏ
Missing some fields (usually creation date due to registry policy) โ Still useful but incomplete
Major TLDs with partial data:
- ๐ฉ๐ช
.de(Germany) - No creation date (registry policy) - ๐ซ๐ท
.fr(France) - No creation date - ๐ฌ๐ง
.uk(United Kingdom) - No creation date - ๐จ๐ณ
.cn(China) - No creation date - ๐ฆ๐บ
.au(Australia) - No creation date - ๐ฆ๐น
.at(Austria) - No creation date - ๐ง๐ช
.be(Belgium) - No creation date - ๐ฉ๐ฐ
.dk(Denmark) - No creation date - ๐ณ๐ฑ
.nl(Netherlands) - Partial data - ๐ต๐ฑ
.pl(Poland) - Partial data - ๐ช๐ธ
.es(Spain) - Authorization required - ๐จ๐ญ
.ch(Switzerland) - Blocks automated queries - ๐ฎ๐ณ
.in(India) - Partial data - ๐ง๐ท
.br(Brazil) - Partial data - ๐จ๐ฆ
.ca(Canada) - Partial data - ๐ช๐บ
.eu(European Union) - No creation date
Server infrastructure issues, cannot be fixed by parser
Breakdown by error type:
- โฑ๏ธ 8 Timeouts (>30s):
.dz.gp.mw.ng.pt.sb.tk.uy - ๐ซ 4 Refused:
.bo.cf.hm.pf - ๐ 2 DNS Error:
.iq.mz - ๐ญ 1 No Data:
.bn - ๐ 3 Connection Reset:
.trand others
- Parser Success: 151/169 (89%) return SOME data
- Full Success: 52/169 (31%) return ALL data
- Infrastructure Issues: 18/169 (11%) cannot be queried at all
The 99 "partial data" ccTLDs are often policy limitations, not bugs:
- European registries hiding creation dates for GDPR compliance
- Some registries require authorization for automated queries
- Privacy-focused registries redacting sensitive information
- ๐ฏ๐ต Japan (.jp) - Square bracket format with Japanese fields
- ๐ฐ๐ท South Korea (.kr) - Korean/English dual format with wide spacing
- ๐ฌ๐ฌ Guernsey (.gg), ๐ฏ๐ช Jersey (.je) - Natural language dates
- ๐ท๐บ Russia (.ru) - Cyrillic field names with IP-annotated nameservers
- ๐ฎ๐น Italy (.it) - Multi-line nameserver sections
- ๐ฉ๐ช Germany (.de) - Nserver format
- Date Normalization: Converts all date formats to ISO 8601 (
YYYY-MM-DDTHH:MM:SSZ) - Multi-Format Parsing: Handles colon-separated, square bracket, and multi-line formats
- Domain Fallback: Uses input domain when WHOIS doesn't return it explicitly
- Robust Error Handling: Custom error classes for different failure types
- Availability Detection:
isDomainAvailable()recognizes "not registered" responses across 20+ registry formats - Rate-Limit Detection:
isRateLimited()distinguishes throttling/access denials (.ch, .es, .it quotas) from real data - Comprehensive Testing: 160+ unit tests with Vitest framework, fixtures for 13 registry formats
- Status Code Normalization: Normalize registry status codes to EPP standard
- Field Mapping Dictionary: Centralized field name aliases for extensibility
- Zero Runtime Dependencies: Only uses Node.js built-in modules
Field extraction was rewritten from free-text regex matching to line-oriented
key/value parsing driven by the alias lists in field-mappings.js. This fixes
a class of wrong-data bugs (substring false-positives, values captured from
the wrong line) and adds support for sectioned formats: .uk (Nominet),
.it, .nl, .ee, .dk, .fi and more. Single-line state: (.ru) and
Japanese [็ถๆ
] statuses are now parsed (previously silently dropped).
import { parseWhoisData, isDomainAvailable, isRateLimited } from '@domaindetails/whois-parser';
const parsed = parseWhoisData(rawText, 'example.de');
parsed.isAvailable; // true when the registry says the domain is not registered
parsed.isRateLimited; // true when the response is a quota/access denial, not dataPreviously consumers had to maintain their own "no match" pattern lists; those were broad enough to misclassify real records. Detection now lives here, with line-anchored per-registry patterns.
parseWhoisData() additionally returns registrarUrl, registrarIanaId,
registrarWhoisServer (referral target for thin registries),
abuseContactEmail, and registrantCountry. When the registrant name is
privacy-redacted, the parser now falls back to the first non-redacted
registrant field (e.g. Registrant Organization).
whoisQuery() now converts IDN domains to punycode, uses server-specific
query formats (whois.denic.de -T dn,ace, whois.jprs.jp /e English output,
Verisign domain prefix), tolerates registries that close connections
abruptly after sending data, and caps response size (1 MiB default,
configurable via options.maxResponseBytes).
New formats normalized to ISO 8601: 01-Dec-2023 (.uk/.ie), 12.6.2006
(.fi), 2002.09.19 13:00:00 (.pl), 20240304 13:11:29 (.at),
2025/06/01 01:05:04 (JST) (.jp), short timezone offsets (+03 โ +03:00),
and Updated Date/Changed fields are now normalized too. Unparseable
values (e.g. .uk before Aug-1996) pass through unchanged.
Handle different error types programmatically:
import {
whoisQuery,
ConnectionError,
TimeoutError,
NoDataError,
ValidationError,
} from '@domaindetails/whois-parser';
try {
const result = await whoisQuery('google.jp', 'whois.jprs.jp');
} catch (error) {
if (error instanceof TimeoutError) {
console.log(`Server timed out after ${error.timeoutMs}ms`);
} else if (error instanceof ConnectionError) {
console.log(`Connection failed to ${error.server}`);
} else if (error instanceof ValidationError) {
console.log(`Invalid ${error.field}`);
}
}Normalize different registry status formats to standard EPP codes:
import { normalizeStatus, isActive, hasTransferLock } from '@domaindetails/whois-parser/status-codes';
// Normalize various formats to EPP codes
normalizeStatus('active'); // โ 'ok'
normalizeStatus('REGISTERED, DELEGATED'); // โ 'ok'
normalizeStatus('locked'); // โ 'clientTransferProhibited'
// Check domain status
isActive(['ok', 'clientTransferProhibited']); // โ true
hasTransferLock(['clientTransferProhibited']); // โ trueAccess the centralized field name aliases:
import { NAMESERVER_FIELDS, getFieldAliases } from '@domaindetails/whois-parser/field-mappings';
// Get all aliases for nameserver fields
console.log(getFieldAliases('nameserver'));
// ['Name Server', 'Nameserver', 'nserver', 'Host Name', 'ํธ์คํธ์ด๋ฆ', ...]The whois_dict.json file is automatically synced with the IANA Root Zone Database.
# Install dependencies first
npm install
# Sync WHOIS servers from IANA (updates whois_dict.json)
npm run sync-iana
# Preview changes without saving
npm run sync-iana:dry-runThe sync script:
- Fetches complete TLD list from
https://data.iana.org/TLD/tlds-alpha-by-domain.txt(1,439 TLDs) - Gets WHOIS server for each TLD from individual IANA pages
- Updates
whois_dict.jsonwith sorted results - Creates dated backups before making changes
- Updates README with last sync date
A GitHub Action automatically syncs the dictionary:
- On every push to main/master branch
- Weekly on Sunday at 2 AM UTC to catch IANA updates
- Manual trigger via GitHub Actions UI
When changes are detected, the action:
- Updates
whois_dict.jsonwith new/changed TLD servers - Updates README with current date
- Creates dated backups
- Commits and pushes changes automatically
See .github/workflows/sync-iana.yml for details.
npm install @domaindetails/whois-parserimport { parseWhoisData, whoisQuery } from '@domaindetails/whois-parser';
// Query a WHOIS server
const whoisText = await whoisQuery('google.jp', 'whois.jprs.jp');
// Parse the response
const parsed = parseWhoisData(whoisText, 'google.jp');
console.log(parsed);
// {
// domainName: 'GOOGLE.JP',
// registrar: 'Google LLC',
// creationDate: '2005-05-30T00:00:00Z',
// expirationDate: '2026-05-31T00:00:00Z',
// nameservers: ['ns1.google.com', 'ns2.google.com', ...],
// registrant: 'Google LLC',
// status: ['Active', 'DomainTransferLocked', 'AgentChangeLocked'],
// dnssec: null,
// lastModified: '2025-06-01T01:05:04.000Z'
// }Run the comprehensive test suite:
# Quick test (19 popular ccTLDs, ~30 seconds)
npm run test:sample
# Full test (all 169 ccTLDs, ~5 minutes)
npm test[1/169] Testing .jp (google.jp)...
โ
OK (domain: GOOGLE.JP, created: 2005-05-30T00:00:00Z)
[2/169] Testing .kr (naver.kr)...
โ
OK (domain: naver.kr, created: 2007-03-02T00:00:00Z)
========== SUMMARY ==========
โ
Successful: 52/169
โ ๏ธ Parsing Issues: 99/169
โ Failed: 18/169
2005/05/30 โ 2005-05-30T00:00:00Z (.jp)
2007. 03. 02. โ 2007-03-02T00:00:00Z (.kr)
30th April 2003 โ 2003-04-30T00:00:00Z (.gg, .je)
30th April each year โ 2026-04-30T00:00:00Z (recurring)
2005-02-14T20:35:14.765Z โ 2005-02-14T20:35:14.765Z (standard)
Square Brackets (.jp):
[Domain Name] GOOGLE.JP
[Name Server] ns1.google.com
[็ป้ฒๅนดๆๆฅ] 2005/05/30
Colon-Separated (most ccTLDs):
Domain Name: google.kr
Registered Date: 2007. 03. 02.
Host Name: ns1.google.com
Dotted Format (.ax, .kz):
domain...............: test.ax
Multi-Line (.gg, .je, .it):
Name servers:
ns1.google.com
ns2.google.com
Some registries (.de, .be, .dk, .at, .im) don't publicly expose creation dates via WHOIS. This is a registry policy, not a parser limitation.
6 ccTLDs still timeout even at 30 seconds: .dz, .gp, .mw, .ng, .sb, .tk
Some WHOIS servers are permanently offline or block automated queries: .bo, .cf, .ch, .es, .hm, .iq, .mz, .pf, .tr
Found a ccTLD that doesn't parse correctly? We'd love a PR!
- Run the test suite to identify the failing TLD
- Query the WHOIS server manually:
whois -h <server> <domain> - Identify the unique format patterns
- Update
parseWhoisData()with new patterns - Re-run tests to verify
| Feature | @domaindetails/whois-parser | whoiser | whois | whois-parsed |
|---|---|---|---|---|
| ccTLD Coverage | 169 TLDs tested | Basic | Basic | Basic |
| Date Format Support | 24+ formats | Basic | None | Basic |
| Japanese/Korean/Russian | Full support | Limited | None | Limited |
| Custom Error Classes | Yes | No | No | No |
| Status Normalization | EPP codes | No | No | No |
| Field Mappings | Extensible | No | No | Hardcoded |
| Zero Runtime Deps | Yes | No | No | No |
| Test Coverage | 76+ tests | Good | Good | Poor |
| Active Maintenance | Yes | Yes | Yes | Stale (3yr) |
| SOCKS Proxy | No | No | Yes | Yes |
| Auto TLD Discovery | Via dictionary | Yes | No | No |
Our differentiator: Best-in-class ccTLD WHOIS parsing with comprehensive international format support, custom error handling, and zero runtime dependencies.
- Built by: DomainDetails.com team
- Special thanks: @synozeer for spotting .gg and other ccTLD issues
- Powered by: Claude Code for the comprehensive parser refactor
MIT License - feel free to use in your projects!
- whois - Node.js WHOIS client
- whoiser - Alternative WHOIS parser
- DomainDetails.com - Free domain lookup tool using this parser
Found this useful? Give us a star โญ at github.com/simplebytes-com/whois-parser and check out DomainDetails.com!