# Domain Age Checker: Registration Date, Expiry & RDAP Lookup (`data-done-right/domain-age-checker`) Actor

Domain age checker for lists of domains. Get registration date, expiry date, age in years, days until expiry, registrar, status flags, nameservers and DNSSEC through public RDAP, the structured successor of WHOIS. No scraping, no personal registrant data. Pay per domain with dates found.

- **URL**: https://apify.com/data-done-right/domain-age-checker.md
- **Developed by:** [Data Done Right](https://apify.com/data-done-right) (community)
- **Categories:** SEO tools, Developer tools, Agents
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.60 / 1,000 domain checkeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Domain Age Checker: Registration Date, Expiry & RDAP Lookup

This domain age checker takes a list of domains and returns one row per domain with the registration date, expiry date, age in years, days until expiry, registrar, status flags, name servers and DNSSEC. It reads the public RDAP service of each registry (RDAP is the structured, JSON successor of WHOIS), so there is no scraping of WHOIS web pages, no login and no API key.

Paste a few domains or up to 20,000. URLs and subdomains are reduced to the registrable domain, every domain is looked up on its own, and one failing lookup never stops the run. Export the result as JSON, CSV or Excel, or call it from the API, Make, Zapier or n8n.

### What does the domain age checker return?

- **Dates:** `registrationDate`, `expiryDate` and `lastChangedDate` (ISO 8601, UTC), taken from the registry's RDAP events.
- **Age and expiry maths:** `ageDays`, `ageYears`, `daysUntilExpiry` (negative when expired), `isExpired`, and `expiringSoon` (you choose the window, 30 days by default).
- **Registrar:** `registrar` (company name) and `registrarIanaId`.
- **Status flags:** the raw `rdapStatus` list plus `transferLocked`, `onHold` and `pendingDelete`.
- **DNS data:** `nameservers` and `dnssecSigned`.
- **Source and result:** `registrySource` (which RDAP server answered), `tld`, a `status` and a plain-language `error` when no dates could be returned.

`status` is one of `ok`, `found-no-dates`, `not-registered`, `not-found`, `rdap-unavailable`, `rate-limited`, `error` or `invalid`. A domain with no RDAP service gets `rdap-unavailable` and empty fields. The Actor never invents data and never falls back to scraping.

### How to check domain age in bulk

1. Open the Input tab and add domains to **Domains to check**, one per line, or paste a block into **Or paste domains**.
2. Optional: set **Expiring-soon window (days)** to flag domains that are about to expire.
3. Click Start. The Overview table shows registration date, expiry date, age and registrar. Other views show expiry and registration details, and a list of domains that were not found.
4. Download the dataset as JSON, CSV or Excel, or read the SUMMARY record for counts, the oldest and newest domain and the next five domains to expire.

### Domain registration date and expiry date lookup

The registration date is the creation event in the registry record, so it shows when the domain name was first registered, which is what most "domain age" questions mean. It is not the first time a website was online. The expiry date is the registry's expiration event; use `daysUntilExpiry` and `expiringSoon` to build an expiry watchlist, and schedule the Actor to re-check it daily or weekly.

### Input example

```json
{
  "domains": ["python.org", "apify.com", "https://blog.example.co.uk/post"],
  "expiryWarningDays": 60,
  "maxDomains": 1000
}
```

### Output example

```json
{
  "domain": "python.org",
  "inputDomain": "python.org",
  "tld": "org",
  "status": "ok",
  "registrationDate": "1995-03-27T05:00:00Z",
  "expiryDate": "2033-03-28T05:00:00Z",
  "lastChangedDate": "2026-08-12T05:01:11Z",
  "ageDays": 11540,
  "ageYears": 31.59,
  "daysUntilExpiry": 2341,
  "isExpired": false,
  "expiringSoon": false,
  "registrar": "Gandi SAS",
  "registrarIanaId": "81",
  "rdapStatus": ["client transfer prohibited"],
  "transferLocked": true,
  "onHold": false,
  "pendingDelete": false,
  "nameservers": ["ns-1134.awsdns-13.org", "ns-2046.awsdns-63.co.uk"],
  "dnssecSigned": false,
  "registrySource": "rdap.publicinterestregistry.org",
  "rdapUrl": "https://rdap.publicinterestregistry.org/rdap/domain/python.org",
  "error": null,
  "checkedAt": "2026-10-29T22:31:02Z"
}
```

### Use with AI agents / MCP

Connect Apify's MCP server (mcp.apify.com) to Claude, ChatGPT or Cursor and an agent can answer questions such as "Which of these 300 domains are younger than one year?" or "Which of our domains expire in the next 60 days?". The agent only needs the `domains` field and reads `ageYears`, `expiryDate` and `expiringSoon` from the dataset.

### Use cases

- **SEO and link building:** judge the age of prospect and backlink domains; filter out brand-new domains.
- **Domain portfolio monitoring:** schedule a daily run and alert on `expiringSoon` or `isExpired`.
- **Fraud, phishing and brand protection:** newly registered look-alike domains are a common warning sign.
- **Due diligence and domain buying:** compare registration date, registrar, status locks and DNSSEC for a shortlist.
- **Data enrichment:** add domain age and registrar to a CRM or lead list.

### Privacy and legality

The Actor uses RDAP, the public protocol that registries publish for exactly this purpose. It does **not return registrant, admin or technical contact data** (names, e-mails, phone numbers or addresses). Only the registrar company, dates, status flags, name servers and DNSSEC are read; contact entities in the registry answer are ignored by the code. Many registries redact that data anyway.

### How the lookups work, and the limits

- **Server choice.** The right RDAP server for each TLD is read from the official IANA RDAP bootstrap file (cached for the run). If a registry server fails, or the IANA file cannot be loaded, the public redirector rdap.org is tried.
- **No RDAP, no data.** Some TLDs, including many country codes, publish no RDAP service. They are reported as `rdap-unavailable`. We do not scrape WHOIS web pages as a workaround.
- **Some registries publish fewer fields.** For example, the .uk registry does not publish an expiry date, so `expiryDate` and the expiry fields are empty for .uk domains while the registration date is there. Domains with at least one date are charged; `found-no-dates` rows are not.
- **Rate limits.** Registries throttle. At most 4 requests run in parallel against one server, and HTTP 429 is retried with backoff, honouring `Retry-After`. If a registry keeps refusing, the row shows `rate-limited`. Lower the concurrency or enable the proxy option and run those domains again.
- **Fresh data, not history.** You get the current registry record. There is no ownership history, no Wayback data, and no check of whether a website is live.
- **Subdomains.** `blog.example.com` is checked as `example.com`. Multi-part suffixes such as co.uk and com.au are handled with the Public Suffix List. Private suffixes such as github.io are not treated as registrable domains.
- **Not for IP addresses**, and no bulk zone-file or newly-registered-domain feeds.

### How much does it cost

Pay per event: **$0.002 per domain (event `domain-checked`), which is $2 per 1,000 domains**, and there is no start fee. You are charged only for a domain when the registry returned a registration or expiry date. Invalid entries, unregistered domains, TLDs without RDAP, rate-limited lookups and errors are free. Duplicates are removed before checking. Checking 5,000 domains costs about $10 at most. Set **Maximum domains** and your Apify spending limit to cap a run; the Actor stops cleanly when the limit is reached and says so in the status message.

### FAQ

#### Is this the same as a WHOIS lookup?

It answers the same questions from the same registries, but through RDAP, which returns structured JSON and is the protocol ICANN requires registries and registrars to run. Port-43 WHOIS text and WHOIS web pages are not used.

#### How is domain age calculated?

From the registry's registration event to the moment of the check: `ageDays` in whole days and `ageYears` with two decimals. A domain that was dropped and re-registered shows the newest registration date.

#### Why is a domain `rdap-unavailable`?

Its TLD registry does not publish an RDAP service in the IANA bootstrap file, so there is nothing reliable to read. The row says so instead of guessing.

#### What is the difference between `not-registered` and `not-found`?

`not-registered` means the TLD's own RDAP server said the domain does not exist. `not-found` is used only when the IANA file could not be loaded and rdap.org had no record, so the reason (not registered, or no RDAP for that TLD) cannot be told apart.

#### Does it show who owns the domain?

No. Registrant names, e-mails and phone numbers are not output. You get the registrar company and technical registry data only.

#### Why are some expiry dates missing?

A few registries (for example .uk) do not publish expiry dates over RDAP. The registration date and other fields are still returned.

### Related tools

- **HTTP Status Code Checker: Bulk URL, Website & Redirect Chains** checks that the sites on your list actually respond and where they redirect.
- **SEO Audit Tool & Meta Tag Checker: Crawler, Broken Links** audits the pages of a site once you have vetted its domain.

# Actor input Schema

## `domains` (type: `array`):

Domains to look up, one per line (use Bulk edit to paste a long list). URLs and subdomains are reduced to the registrable domain, so https://blog.example.co.uk/page becomes example.co.uk. Duplicates are removed.

## `domainsText` (type: `string`):

Alternative to the list above: paste a block of domains or URLs separated by new lines, commas or spaces. Added after the list; duplicates across both are removed.

## `maxDomains` (type: `integer`):

Upper limit of unique domains to check in this run. This also caps the cost.

## `expiryWarningDays` (type: `integer`):

A domain is flagged expiringSoon when it expires within this many days (and has not expired yet).

## `concurrency` (type: `integer`):

Domains looked up in parallel. At most 4 requests run in parallel against the same registry server, and rate limits (HTTP 429) are retried with backoff.

## `proxyConfiguration` (type: `object`):

Off by default; RDAP is a public API. Turn it on only if a registry rate-limits the run's IP address.

## Actor input object example

```json
{
  "domains": [
    "python.org",
    "apify.com",
    "example.com"
  ],
  "maxDomains": 1000,
  "expiryWarningDays": 30,
  "concurrency": 10,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

One row per domain: registration date, expiry date, age, registrar, status flags, nameservers and DNSSEC (all result items of this run, as JSON, CSV, Excel and more).

## `summary` (type: `string`):

SUMMARY record: counts by status and TLD, expired and expiring-soon domains, oldest and newest domain, next to expire, and any notes.

## `records` (type: `string`):

Key-value store records of this run (SUMMARY and any other files).

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "domains": [
        "python.org",
        "apify.com",
        "example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("data-done-right/domain-age-checker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "domains": [
        "python.org",
        "apify.com",
        "example.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("data-done-right/domain-age-checker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "domains": [
    "python.org",
    "apify.com",
    "example.com"
  ]
}' |
apify call data-done-right/domain-age-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,data-done-right/domain-age-checker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/tNIZUNW8NGjSAYcCT/builds/3qZ1aHktajv4R53jh/openapi.json
