Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions app/(site)/(catalogs)/[slug]/content/domain-tools/article.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ Find the question you're asking.

## Is WHOIS still used?

Mostly not. ICANN stopped requiring WHOIS for most generic endings, such as `.org`, on 28 January 2025, and RDAP replaced it. People still call it a WHOIS lookup, but the lookup tools here read RDAP only. The [domain lookup](/domain-lookup) page explains how the two differ.
Less and less. ICANN stopped requiring WHOIS for most generic endings, such as `.org`, on 28 January 2025, and RDAP replaced it. Some country endings, such as `.it`, `.eu`, and `.jp`, still offer only WHOIS. The tools here use RDAP when the registry offers it and the registry's WHOIS server when it doesn't. The [domain lookup](/domain-lookup) page explains how the two differ.

## Can every domain ending be looked up?

No. Some endings, mostly country endings, don't publish RDAP. For those, the tools say they can't check the name, which doesn't mean it's free. The [TLD directory](/tld-directory) shows which endings can be looked up and links each registry.
Most can, but not all. A few endings, mostly small country endings, have no lookup service the tools can use. For those, the tools say they can't check the name, which doesn't mean it's free. The [TLD directory](/tld-directory) shows how each ending is checked and links each registry.

## Can I see who owned a domain before?

No. RDAP returns only the current record, with no past owners or old nameservers. Sites that show history use copies they saved over time.
No. The registry returns only the current record, with no past owners or old nameservers. Sites that show history use copies they saved over time.

## What happens to the names I look up?

Expand Down
7 changes: 4 additions & 3 deletions app/(site)/(directories)/tld-directory/content/lookups.mdx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
## Why can't some domain extensions be looked up?

Our domain tools read registration data over RDAP, and some registries don't offer it. The Lookups column shows where each ending stands.
Our domain tools ask each ending's registry over RDAP when it offers it, and over WHOIS when it doesn't. A few registries offer neither in a form we can use. The Lookups column shows where each ending stands.

| Lookups | What it means |
| --- | --- |
| Yes | The registry is in [IANA's RDAP directory](https://data.iana.org/rdap/dns.json). |
| Via our own list | The registry runs RDAP but isn't in IANA's directory. We added it after testing it with a real domain. The name under the label runs the service. |
| Cannot check | We know of no RDAP service for this ending, so our lookup and availability tools can't answer for it. |
| Via WHOIS | The registry has no RDAP service we know of, so we read its WHOIS server. We added it after testing it with a real domain and a made-up one. WHOIS text can leave out fields that RDAP would show. |
| Cannot check | We know of no RDAP service, and the WHOIS server is missing or didn't pass our tests. Our lookup and availability tools can't answer for this ending. |

A "Cannot check" ending may still have a WHOIS server or a lookup on the registry's website. Its page in [IANA's root zone database](https://www.iana.org/domains/root/db) lists both. [Domain lookup](/domain-lookup) explains how RDAP and WHOIS differ.
A "Cannot check" ending may still have a lookup on the registry's website. Its page in [IANA's root zone database](https://www.iana.org/domains/root/db) links to it. [Domain lookup](/domain-lookup) explains how RDAP and WHOIS differ.
2 changes: 1 addition & 1 deletion app/(site)/(directories)/tld-directory/content/sources.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

- Type and operator: [IANA's root zone database](https://www.iana.org/domains/root/db).
- DNSSEC: DS records in the [root zone file](https://www.internic.net/domain/root.zone).
- Lookups: [IANA's RDAP directory](https://data.iana.org/rdap/dns.json), plus the few registries we added by hand.
- Lookups: [IANA's RDAP directory](https://data.iana.org/rdap/dns.json), the RDAP services we added by hand, and WHOIS servers listed in IANA's root zone database that passed our tests.

A script rebuilds the table from these sources. If a source changes shape, the script stops instead of saving a partial list.
4 changes: 3 additions & 1 deletion app/(site)/(directories)/tld-directory/tld-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type TldRow = {
unicode: string | null;
type: string | null;
organisation: string | null;
rdap: "bootstrap" | "override" | "none";
rdap: "bootstrap" | "override" | "whois" | "none";
rdapOperator: string | null;
dnssec: boolean;
isIdn: boolean;
Expand Down Expand Up @@ -124,6 +124,8 @@ export function TldTable({ rows }: { rows: TldRow[] }) {
<StatePill tone="quiet">Cannot check</StatePill>
) : row.rdap === "override" ? (
<StatePill tone="warn">Via our own list</StatePill>
) : row.rdap === "whois" ? (
<StatePill tone="warn">Via WHOIS</StatePill>
) : (
<StatePill tone="good">Yes</StatePill>
)}
Expand Down
2 changes: 1 addition & 1 deletion app/(site)/(tools)/domain-age/domain-age-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function unavailableResult(result: DomainRegistration) {
if (result.status === "no_service") {
return (
<UiPrimaryResult
detail={`No RDAP registration service is published for .${result.query.tld}.`}
detail={`stack127 has no lookup service it can use for .${result.query.tld}.`}
label="Domain age"
tone="warning"
value="Unavailable"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ function AvailabilityResult({ result }: { result: DomainRegistration }) {

{result.status === "no_service" ? (
<p className={styles.recovery}>
See RDAP coverage in the <Link href="/tld-directory">TLD directory</Link>.
See which endings we can check in the <Link href="/tld-directory">TLD directory</Link>.
</p>
) : null}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function formatAvailabilityDate(value: string | null) {
}

function failureDetail(status: RdapFetchStatus, tld: string) {
if (status === "no_service") return `stack127 has no known RDAP service for .${tld}.`;
if (status === "no_service") return `stack127 has no lookup service it can use for .${tld}.`;
if (status === "rate_limited") return "The registry limited this request. Try again shortly.";
if (status === "blocked") return "The registry refused this request. Try again shortly.";
if (status === "timeout") return "The registry did not answer in time. Try again.";
Expand Down
2 changes: 1 addition & 1 deletion app/(site)/(tools)/domain-expiry/domain-expiry-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ function unavailableAnswer(result: DomainRegistration) {
return <UiPrimaryResult detail={`${result.query.unicode} has no current expiry date.`} label="Domain expiry" value="Not registered" />;
}
if (result.status === "no_service") {
return <UiPrimaryResult detail={`No RDAP registration service is published for .${result.query.tld}.`} label="Domain expiry" tone="warning" value="Unavailable" />;
return <UiPrimaryResult detail={`stack127 has no lookup service it can use for .${result.query.tld}.`} label="Domain expiry" tone="warning" value="Unavailable" />;
}
if (result.status === "rate_limited" || result.status === "blocked") {
return <UiPrimaryResult detail="The registry limited this request. Try again in a few minutes." label="Domain expiry" tone="warning" value="Could not check" />;
Expand Down
6 changes: 4 additions & 2 deletions app/(site)/(tools)/domain-lookup/content/article.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

RDAP is the newer way to read public domain registration data, and it replaced WHOIS for generic endings such as `.com` and `.org`. Both read the same registry records. RDAP returns labeled fields and standard event dates, and can declare which data is withheld. WHOIS returns free text that differs by provider.

Since 28 January 2025, ICANN no longer requires generic registries and registrars to run WHOIS, except for `.com`, `.name`, and `.post`. [ICANN's RDAP page](https://www.icann.org/rdap) explains the change. This lookup uses RDAP only.
Since 28 January 2025, ICANN no longer requires generic registries and registrars to run WHOIS, except for `.com`, `.name`, and `.post`. [ICANN's RDAP page](https://www.icann.org/rdap) explains the change. This lookup uses RDAP whenever the registry offers it.

Country endings such as `.uk` or `.de` set their own rules. Some publish RDAP and some don't. When an ending has none, the result shows `Cannot determine`, which says nothing about whether the name is registered. Use the registry's own lookup, which the ending's page in [IANA's root zone database](https://www.iana.org/domains/root/db) links to. The [TLD directory](/tld-directory) shows which endings have RDAP.
Country endings such as `.uk` or `.it` set their own rules. Many publish RDAP, and some offer only WHOIS. For those, the lookup asks the registry's WHOIS server and reads the text into the same fields: dates, registrar, statuses, and nameservers. A field the text doesn't clearly state stays unknown, and the source line names the server, such as `whois.nic.it`.

A few endings offer neither, or their WHOIS server didn't pass our tests. For those, the result shows `Cannot determine`, which says nothing about whether the name is registered. Use the registry's own lookup, which the ending's page in [IANA's root zone database](https://www.iana.org/domains/root/db) links to. The [TLD directory](/tld-directory) shows how each ending is checked.

A WHOIS site can show different details because it reads WHOIS text or an older saved copy. Owner details are a separate question, covered in the [registrant lookup](/domain-owner).

Expand Down
2 changes: 1 addition & 1 deletion app/(site)/(tools)/domain-lookup/domain-lookup-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ function LookupResult({ result }: { result: DomainRegistration }) {
<SourceMap result={result} />
{registrarFailure ? <UiStatus tone="warning">The registrar response was incomplete. Registry facts remain available.</UiStatus> : null}
{registered ? <><Dates result={result} /><RegistrarFacts result={result} /><Statuses result={result} /><Nameservers result={result} /><Dnssec result={result} /><Contacts result={result} /></> : null}
{result.status === "no_service" ? <p className={styles.recovery}>See RDAP coverage in the <Link href="/tld-directory">TLD directory</Link>.</p> : null}
{result.status === "no_service" ? <p className={styles.recovery}>See which endings we can check in the <Link href="/tld-directory">TLD directory</Link>.</p> : null}
<Freshness result={result} />
<div className={styles.download}><UiDownloadAction contents={report} filename={`${result.query.domain}-registration.json`} label="Download report" mimeType="application/json;charset=utf-8" /></div>
{notes.length ? <UiDisclosure label="Lookup notes"><ul className={styles.notes}>{notes.map((note) => <li key={note}>{note}</li>)}</ul></UiDisclosure> : null}
Expand Down
2 changes: 1 addition & 1 deletion app/(site)/(tools)/domain-lookup/domain-lookup-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function statusClause(result: DomainRegistration) {
}

function unavailableDetail(status: RdapFetchStatus, tld: string) {
if (status === "no_service") return `stack127 has no known RDAP service for .${tld}.`;
if (status === "no_service") return `stack127 has no lookup service it can use for .${tld}.`;
if (status === "rate_limited") return "The registry limited this request. Try again shortly.";
if (status === "blocked") return "The registry refused this request. Try again shortly.";
if (status === "timeout") return "The registry did not answer in time. Try again.";
Expand Down
2 changes: 1 addition & 1 deletion app/(site)/(tools)/domain-owner/domain-owner-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ function OwnerResult({ result }: { result: DomainRegistration }) {
<SourceMap result={result} />
{registrarFailure ? <UiStatus tone="warning">{result.registrarFetch ? "The registrar response failed." : "The registry did not advertise a registrar response."} Retry the lookup before treating missing contact data as unpublished.</UiStatus> : null}
{registered ? <><ContactRoutes result={result} verdict={verdict} /><PublishedFields result={result} /><Redactions result={result} /><p className={styles.broader}><Link href={`/domain-lookup?name=${encodeURIComponent(result.query.unicode)}`}>See the full registration record</Link> for dates, status, nameservers, and DNSSEC.</p></> : null}
{result.status === "no_service" ? <p className={styles.recovery}>See RDAP coverage in the <Link href="/tld-directory">TLD directory</Link>.</p> : null}
{result.status === "no_service" ? <p className={styles.recovery}>See which endings we can check in the <Link href="/tld-directory">TLD directory</Link>.</p> : null}
<Freshness result={result} />
{notes.length ? <UiDisclosure label="Lookup notes"><ul className={styles.notes}>{notes.map((note) => <li key={note}>{note}</li>)}</ul></UiDisclosure> : null}
<div className={styles.download}><UiDownloadAction contents={report} filename={`${result.query.domain}-registrant.json`} label="Download report" mimeType="application/json;charset=utf-8" /></div>
Expand Down
11 changes: 10 additions & 1 deletion app/(site)/(tools)/domain-owner/domain-owner-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,16 @@ function identityValues(result: DomainRegistration) {
}

function failureDetail(status: RdapFetchStatus, tld: string) {
if (status === "no_service") return `stack127 has no known RDAP service for .${tld}.`;
if (status === "no_service") return `stack127 has no lookup service it can use for .${tld}.`;
if (status === "rate_limited") return "The registry limited this request. Try again shortly.";
if (status === "blocked") return "The registry refused this request. Try again shortly.";
if (status === "timeout") return "The registry did not answer in time. Try again.";
return "The registry did not return a usable answer. Try again.";
}

export function isRegistrarHopIncomplete(result: DomainRegistration) {
// WHOIS registries have no registrar hop, so nothing is missing.
if (result.registryFetch?.protocol === "whois") return false;
if (result.registrarFetch) return result.registrarFetch.status !== "registered";
return Boolean(result.registrar.name || result.registrar.ianaId || result.registrar.rdapUrl);
}
Expand Down Expand Up @@ -101,6 +103,13 @@ export function ownerVerdict(result: DomainRegistration) {
};
}

if (result.registryFetch?.protocol === "whois") {
return {
detail: `The registry's WHOIS record for ${result.query.unicode} names no registrant. WHOIS doesn't say why a field is left out.`,
value: "Not published",
};
}

const declared = declaredSources(result);
if (declared.length) {
const providers = declared.length === 2 ? "The registry and registrar declared redaction" : `${declared[0]} declared redaction`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ function RegistrarResult({ result }: { result: DomainRegistration }) {
{registered ? <RegistrarDates result={result} /> : null}
{registered && !identity.conflict ? <NextSteps result={result} /> : null}
{registrarHopFailed ? <UiStatus tone="warning">{result.registrarFetch ? "The registrar response failed." : "The registry did not advertise a registrar response."} Website, alternate-name, and additional abuse details may be missing.</UiStatus> : null}
{result.status === "no_service" ? <p className={styles.recovery}>See RDAP coverage in the <Link href="/tld-directory">TLD directory</Link>.</p> : null}
{result.status === "no_service" ? <p className={styles.recovery}>See which endings we can check in the <Link href="/tld-directory">TLD directory</Link>.</p> : null}
{registered && !identity.name && !identity.id ? <p className={styles.recovery}>Check the wider <Link href={`/domain-lookup?name=${encodeURIComponent(result.query.unicode)}`}>domain registration record</Link>.</p> : null}
<Freshness result={result} />
<div className={styles.download}><UiDownloadAction contents={report} filename={`${result.query.domain}-registrar.json`} label="Download report" mimeType="application/json;charset=utf-8" /></div>
Expand Down
4 changes: 3 additions & 1 deletion app/(site)/(tools)/domain-registrar/domain-registrar-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function registrarIdentity(result: DomainRegistration) {
}
if (result.status !== "registered") {
const reason = result.status === "no_service"
? `stack127 has no known RDAP service for .${result.query.tld}.`
? `stack127 has no lookup service it can use for .${result.query.tld}.`
: result.status === "timeout"
? "The registry did not answer in time. Try again."
: result.status === "rate_limited" || result.status === "blocked"
Expand Down Expand Up @@ -61,6 +61,8 @@ export function registrarIdentity(result: DomainRegistration) {

export function isRegistrarHopIncomplete(result: DomainRegistration) {
if (result.status !== "registered") return false;
// WHOIS registries have no registrar hop, so nothing is missing.
if (result.registryFetch?.protocol === "whois") return false;
if (result.registrarFetch) return result.registrarFetch.status !== "registered";
return Boolean(result.registrar.name || result.registrar.ianaId || result.registrar.rdapUrl);
}
Expand Down
5 changes: 3 additions & 2 deletions app/(site)/(tools)/domain-report/domain-report-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function coverageRows(result: DomainReport) {
id: "registration",
check: "Registration record",
state: registrationDone ? "Completed" : "Unavailable",
source: result.registration?.registryFetch ? host(result.registration.registryFetch.url) ?? "Registry RDAP" : "Not available",
source: result.registration?.registryFetch ? host(result.registration.registryFetch.url) ?? "Registry" : "Not available",
note: registrationDone ? (result.registration?.registryFetch?.fromCache ? "Cached response" : "Registry response") : skippedReason(result, "Registration record"),
},
{
Expand Down Expand Up @@ -120,8 +120,9 @@ export function findingDetail(finding: ReportFinding) {

export function reportSourceRows(result: DomainReport) {
const rows: Array<{ id: string; label: string; value: string }> = [];
for (const [label, fetch] of [["Registry RDAP", result.registration?.registryFetch], ["Registrar RDAP", result.registration?.registrarFetch]] as const) {
for (const [party, fetch] of [["Registry", result.registration?.registryFetch], ["Registrar", result.registration?.registrarFetch]] as const) {
if (!fetch || fetch.status === "no_service") continue;
const label = `${party} ${fetch.protocol === "whois" ? "WHOIS" : "RDAP"}`;
rows.push({ id: label, label, value: `${host(fetch.url) ?? "Host not reported"}, fetched ${formatReportDate(fetch.fetchedAt)}, ${fetch.fromCache ? "cached" : "live response"}` });
}
if (result.delegation) rows.push({ id: "dns", label: "DNS delegation", value: `${result.delegation.zone} via parent .${result.delegation.parentZone}, checked ${formatReportDate(result.delegation.checkedAt)}` });
Expand Down
5 changes: 2 additions & 3 deletions app/(site)/(tools)/multi-tld-availability/multi-tld-tool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ import {
} from "./multi-tld-view";
import styles from "./multi-tld-tool.module.css";

const OPTIONAL_TLDS = ["co", "me", "us", "de", "uk", "site", "online", "tech"];
const OPTIONAL_TLDS = ["co", "me", "so", "sh", "gg", "to", "eu", "us", "de", "uk", "site", "online", "tech"];
const ALL_TLDS = [...DEFAULT_TLDS, ...OPTIONAL_TLDS];
const NO_RDAP_SERVICE = new Set(["co", "me"]);

class MultiTldRequestError extends Error {
constructor(message: string, readonly fieldError = false) {
Expand Down Expand Up @@ -290,7 +289,7 @@ export function MultiTldTool() {
key={tld}
onChange={() => toggle(tld)}
>
<span className={styles.choiceLabel}>.{tld}{NO_RDAP_SERVICE.has(tld) ? <small>No RDAP service</small> : null}</span>
<span className={styles.choiceLabel}>.{tld}</span>
</UiCheckbox>
);
})}
Expand Down
4 changes: 2 additions & 2 deletions app/(site)/(tools)/multi-tld-availability/multi-tld-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function multiTldSummary(rows: MultiTldRow[]) {
}

export function resultDetail(row: MultiTldRow) {
if (row.state === "cannot_check") return `No known RDAP service for .${row.tld}`;
if (row.state === "cannot_check") return `No lookup service for .${row.tld}`;
if (row.state === "check_failed") return row.detail || "The registry check failed.";
return null;
}
Expand All @@ -56,7 +56,7 @@ export function formatMultiTldDate(value: string) {
}

export function sourceAndFreshness(row: MultiTldRow) {
if (row.state === "cannot_check") return { freshness: null, source: "No RDAP service" };
if (row.state === "cannot_check") return { freshness: null, source: "No lookup service" };
return {
freshness: row.fetchedAt ? `Fetched ${formatMultiTldDate(row.fetchedAt)}${row.fromCache ? ", from cache" : ", live response"}` : null,
source: row.sourceHost ?? "Registry source not reported",
Expand Down
Loading
Loading