# Domain Registration Lookup — Registrar, Age & Expiry (`alaudinburki/domain-registration`) Actor

Look up any domain's registration record: registrar, creation date, expiry, last change, status flags and nameservers. RDAP — the modern keyless replacement for WHOIS — across every TLD.

- **URL**: https://apify.com/alaudinburki/domain-registration.md
- **Developed by:** [alaudin burki](https://apify.com/alaudinburki) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

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

## 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 Registration Lookup — Registrar, Age & Expiry

Look up any domain's registration record: **registrar, creation date, expiry, last change, status flags
and nameservers** — over RDAP, the standardised, keyless replacement for WHOIS.

### Why RDAP and not WHOIS

WHOIS is plain text with no schema: every registry formats its answer differently, and many now
rate-limit or block it outright. RDAP is JSON over HTTPS, with one bootstrap (`rdap.org`) that redirects
to whichever registry owns the TLD — so **one Actor covers `.com`, `.co.uk`, `.io` and the rest**, the
same "one platform, many sources" leverage the catalogue is built on.

Real output:

```
apify.com   Amazon Registrar, Inc.   created 2009-06-02   expires 2035-06-02   6,348 days old
google.com  MarkMonitor Inc.         created 1997-09-15   expires 2028-09-14  10,626 days old
bbc.co.uk   British Broadcasting Corp created 1994-12-13  expires 2034-12-13  11,633 days old
```

### The distinction this Actor refuses to blur

**"No record" is not "available".**

RDAP answers `404` both for a domain nobody has registered **and** for a TLD whose registry publishes no
RDAP at all. Reporting that as *available* would be a confident wrong answer, so:

- `registered` is **`null`**, not `false`
- `recordFound` is false
- `note` says plainly which two things it could mean

If you need "is this name free", that requires a registrar check, not this record.

### Derived columns that make it useful

| | |
|---|---|
| `ageDays` | Domain age is a standard trust signal — a week-old domain selling something is a different proposition from a decade-old one |
| `daysUntilExpiry` | Positive for a future date; negative means lapsed |
| `isExpiringSoon` | Expiry within **60 days** — the usual registrar warning window, and the filter for a renewal watch |

### Two traps in the data

**The registrar hides in a vCard.** `entities[].vcardArray[1]` is a list of property tuples and the name
is the one whose first element is `fn` — the list starts with `version`, so reading a fixed index returns
`"4.0"`. A unit test asserts the registrar is the name and not the version string.

**Expiry counts in the other direction to age.** Age is `now − created`; expiry is `expires − now`. Using
one helper for both made a 2035 expiry read as **3,148 days overdue** and flag it as expiring soon, which
the live check caught on the first run.

### Limits

- **Only what the registry publishes.** Some TLDs hide registrant details behind GDPR redaction; RDAP
  simply omits them, and this Actor does not invent them.
- A TLD with no RDAP service returns no record, as described above.
- Registration data changes; every row carries `scrapedAt` and the registry endpoint it came from.

### Verified

**27 unit tests** on the reader — the vCard trap, both date directions, the no-record caveat, and input
normalisation — plus **31 live checks** across `.com` and `.co.uk`, including a random non-existent
domain asserted to return `registered: null` rather than `false`.

***

One row per domain, flat, ready for a renewal watch or a due-diligence pass. Built as part of the
ExtractorHub catalogue of production data extractors.

### Fields

| Field | Type | What it holds |
|---|---|---|
| `id` | string | The domain, used as the row identity. |
| `domain` | string | The domain as the registry writes it, lower-cased. |
| `registered` | boolean | True when a registration record exists. **Null — not false — when RDAP had no record**, because that also happens for a TLD whose registry publishes no RDAP. |
| `recordFound` | boolean | Whether RDAP returned anything at all. |
| `registrar` | string | The registrar of record, read from the registrar entity's vCard. |
| `registeredAt` | string | Creation date from the registry. |
| `expiresAt` | string | Expiry date from the registry. |
| `lastChangedAt` | string | Last time the registration record changed — a transfer or status change moves this, not the creation date. |
| `ageDays` | number | Days since registration. Domain age is a standard trust signal: a week-old domain selling something is a different proposition from a decade-old one. |
| `daysUntilExpiry` | number | Days remaining before expiry, positive for a future date. Negative means it has lapsed. |
| `isExpiringSoon` | boolean | True when expiry is within 60 days — the usual registrar warning window, and the filter to schedule against. |
| `statuses` | string | EPP status flags, comma-separated: clientTransferProhibited, ok, pendingDelete and so on. |
| `nameservers` | string | Nameservers, comma-separated. |
| `nameServerCount` | number | How many nameservers are delegated. |
| `note` | string | Present only when the record is missing, and it says plainly that 'no record' does not mean 'available'. |
| `rdapSource` | string | The registry endpoint the bootstrap sent us to, so the answer can be checked. |
| `scrapedAt` | string | When this run read the registry. |

# Actor input Schema

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

Domains such as apify.com or bbc.co.uk. A full URL is accepted and reduced to its host; www is stripped.

## `maxItems` (type: `integer`):

Hard limit. A run that stops early says so.

## `timeoutSecs` (type: `integer`):

Per domain.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "bbc.co.uk"
  ],
  "maxItems": 2000,
  "timeoutSecs": 25
}
```

# Actor output Schema

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

One row per domain, with the 17 fields listed under Views.

# 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": [
        "apify.com",
        "bbc.co.uk"
    ],
    "maxItems": 2000
};

// Run the Actor and wait for it to finish
const run = await client.actor("alaudinburki/domain-registration").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": [
        "apify.com",
        "bbc.co.uk",
    ],
    "maxItems": 2000,
}

# Run the Actor and wait for it to finish
run = client.actor("alaudinburki/domain-registration").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": [
    "apify.com",
    "bbc.co.uk"
  ],
  "maxItems": 2000
}' |
apify call alaudinburki/domain-registration --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,alaudinburki/domain-registration"
        }
    }
}
```

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/Deq5mAvcmY0bZrL94/builds/iFjjV3bdwxTyKoZK4/openapi.json
