# Bulk WHOIS Lookup: Domain Age, Expiry and Availability (`vindr/bulk-whois-lookup`) Actor

Look up many domains at once: registrar, creation and expiry date, domain age, status, name servers and DNSSEC from the official RDAP registries, plus availability, MX, IP and SSL expiry. Check name ideas across TLDs. No owner contact data. $3 per 1,000 domains.

- **URL**: https://apify.com/vindr/bulk-whois-lookup.md
- **Developed by:** [VindR](https://apify.com/vindr) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 domains

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

### What does Bulk WHOIS Lookup do?

Bulk WHOIS Lookup checks many domains at once and tells you who they are registered with, when they were created, when they expire and whether they are still available. Paste a list of domains (or a few name ideas) and get a clean table back, ready for Excel, Google Sheets or your own code.

For every domain you get:

- **Registration data** from the official registry: registrar, creation date, expiry date, last update, domain age, status codes, name servers and DNSSEC.
- **Availability**: registered, available, or likely available.
- **DNS**: MX records (where the domain's email goes) and IP addresses.
- **SSL certificate**: issuer, expiry date, days left and whether it is valid.

The data comes from RDAP, the official successor to WHOIS that the registries themselves run. Contact details of domain owners are never collected.

### Which domains are supported?

Every top-level domain works, but how much you get depends on the registry.

- **Full registration data** for more than 1,200 top-level domains that offer RDAP. This includes .com, .net, .org, .info, .xyz, .app, .dev, .ai, .no, .uk, .nl, .fi, .fr, .pl, .ca, .au, .in and most new domains like .shop or .online.
- **Registered or not, from DNS** for top-level domains whose registry doesn't offer RDAP yet, for example .se, .dk, .de, .eu, .io, .co, .es, .it and .ch. For these you see whether the domain is registered, its name servers, MX records and SSL certificate, but no registrar or dates. The `note` field says so for each domain.

A few registries don't publish every date. Norway (.no) and the Netherlands (.nl), for example, show the creation date but not the expiry date.

### What data do you get?

| Field | Example |
|---|---|
| Domain | google.com |
| Status | registered, available, likely available |
| Registrar and IANA ID | MarkMonitor Inc., 292 |
| Created, updated, expires | 1997-09-15, 2019-09-09, 2028-09-14 |
| Domain age and days until expiry | 29 years, 720 days |
| Domain status codes | client transfer prohibited, server delete prohibited |
| Name servers and DNSSEC | ns1.google.com, ns2.google.com, DNSSEC off |
| MX records and IP addresses | smtp.google.com, 172.217.20.174 |
| SSL certificate | Google Trust Services, expires 2026-12-03, 69 days left, valid |
| Source and note | which registry answered, and anything you should know |

### How to use it

1. Click **Try for free** at the top of this page.
2. Paste your domains into **Domains**, one per line. Full URLs and subdomains are fine: `https://shop.example.co.uk/about` is looked up as `example.co.uk`.
3. Optional: to check if a name is free, add it under **Name ideas** and pick the **Top-level domains** to try.
4. Optional: keep only available domains, only registered ones, or only domains that expire soon.
5. Click **Start**, then download the results as Excel, CSV or JSON, or use the API.

#### Input examples

Look up a list of domains:

```json
{
    "domains": ["google.com", "vipps.no", "bbc.co.uk", "spotify.se"]
}
```

Find out which of your name ideas are still free on .com, .io and .no:

```json
{
    "names": ["northwind", "bluefjord", "quietdata"],
    "tlds": ["com", "io", "no"],
    "onlyStatus": "available"
}
```

Find domains in your portfolio that expire within 60 days:

```json
{
    "domains": ["example.com", "example.net", "example.org"],
    "expiringWithinDays": 60
}
```

### Output example

A registered domain with full RDAP data:

```json
{
    "input": "google.com",
    "domain": "google.com",
    "domainUnicode": null,
    "tld": "com",
    "status": "registered",
    "registered": true,
    "registrar": "MarkMonitor Inc.",
    "registrarIanaId": "292",
    "createdAt": "1997-09-15T04:00:00Z",
    "updatedAt": "2019-09-09T15:39:04Z",
    "expiresAt": "2028-09-14T04:00:00Z",
    "ageYears": 29,
    "daysUntilExpiry": 720,
    "domainStatus": ["client delete prohibited", "client transfer prohibited", "server delete prohibited"],
    "nameservers": ["ns1.google.com", "ns2.google.com", "ns3.google.com", "ns4.google.com"],
    "dnssec": false,
    "mxRecords": ["smtp.google.com"],
    "ipAddresses": ["172.217.20.174"],
    "sslIssuer": "Google Trust Services",
    "sslValidTo": "2026-12-03T19:21:52.000Z",
    "sslDaysLeft": 69,
    "sslValid": true,
    "source": "rdap.verisign.com",
    "note": null,
    "checkedAt": "2026-09-24T22:00:19.135Z"
}
```

A domain that is free:

```json
{
    "domain": "vindrexample.com",
    "status": "available",
    "registered": false,
    "registrar": null,
    "expiresAt": null,
    "source": "rdap.verisign.com",
    "note": "Not registered according to the official registry. Some names are reserved or sold at a premium price, so confirm with a registrar before you count on it."
}
```

Internationalized domains are returned in the form registries use (`xn--rksmrgs-5wao1o.se`), with the readable form in `domainUnicode` (`räksmörgås.se`).

A `RUN_SUMMARY` record in the key-value store shows how many domains were checked and saved, the count per status, any input that was skipped, and domains that could not be checked.

### How much does it cost?

You pay **$3 per 1,000 domains** saved. Server time is included.

- 100 domains cost $0.30. 10,000 domains cost $30.
- Domains removed by your filters are not charged. Checking 300 name ideas to find the 40 that are free costs $0.12.
- Domains that could not be checked (for example when both the registry and DNS fail to answer) are not saved and not charged.
- The $5 in free monthly credit on the Apify free plan covers about 1,600 domains a month.

Set **Max domains in total** or a maximum cost per run if you want a hard budget.

### What can you use it for?

- **Domain portfolio management.** See every domain's registrar and expiry date in one table, and catch domains that are about to expire.
- **Finding a name.** Check dozens of name ideas across several top-level domains in one go.
- **Due diligence and fraud checks.** A domain registered last week deserves more caution than one that is 20 years old.
- **Sales and market research.** Domain age, registrar and DNS setup say a lot about a company.
- **IT and security audits.** Spot SSL certificates that expire soon, domains without DNSSEC, or domains pointing to name servers you don't expect.

### FAQ

#### What is the difference between WHOIS and RDAP?

RDAP is the modern replacement for WHOIS, run by the same registries. It gives the same registration data in a structured format, and since 2025 it is the official source for .com and all other generic top-level domains. You get the data you would look for in WHOIS, without the messy text parsing.

#### What do "available" and "likely available" mean?

**Available** means the official registry says the domain isn't registered. **Likely available** is used for top-level domains without RDAP: the domain doesn't exist in DNS, which almost always means it's free, but a registered domain without name servers looks the same. In both cases, some names are reserved by the registry or sold at a premium price, so always confirm with a registrar before you count on it.

#### Why are the dates missing for some domains?

Either the registry doesn't offer RDAP (see the list above), or it doesn't publish that date (.no and .nl have no expiry date). The `note` field tells you which. The domain is still marked as registered or not, based on DNS.

#### Do you collect the domain owner's name or email?

No. Only the registrar (a company), dates, status codes, name servers and DNSSEC are read from the registry. Owner and contact information is never read or stored, even when a registry shows it.

#### Is it legal?

Yes. RDAP is a public service run by the registries for exactly this kind of lookup, and DNS and SSL certificates are public by design. The Actor spaces out its requests to each registry and slows down when a registry asks it to. As always, you are responsible for how you use the results.

#### How fast is it?

Most registries answer several lookups a second, so 1,000 .com domains take a few minutes. Some registries allow far fewer. The Dutch registry (.nl), for example, only allows about one lookup every few seconds. Every registry gets its own queue, so a slow one never holds up the others.

#### Can I use it from my own code?

Yes. Every Apify Actor has an API. See the **API** tab for examples in Python, JavaScript and plain HTTP. It also works with Make, n8n, Zapier and Google Sheets.

#### Something missing or not working?

Open an issue on the **Issues** tab with the domain you tried.

### More tools from VindR

- [Website Tech Stack Detector](https://apify.com/vindr/website-tech-stack-detector): what a website is built with, plus the same domain age and SSL data.
- [Sitemap Extractor, URL Status and Broken Link Checker](https://apify.com/vindr/sitemap-url-checker): every page of a website, with broken links and redirects.

# Actor input Schema

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

The domains to look up, one per line. Plain domains (<code>example.com</code>), subdomains and full URLs all work: <code>https://shop.example.co.uk/about</code> is looked up as <code>example.co.uk</code>. Duplicates are removed automatically.

## `names` (type: `array`):

Check if a name is free on several top-level domains at once. Add names without a dot, for example <code>mybrand</code>, and pick the top-level domains below. Every name is combined with every top-level domain.

## `tlds` (type: `array`):

Top-level domains to combine with the name ideas, for example <code>com</code>, <code>io</code> or <code>no</code>. Only used together with name ideas.

## `onlyStatus` (type: `string`):

Keep only registered or only available domains. Domains you don't keep are not saved and not charged. "Available" also includes domains that are likely available (see the README).

## `expiringWithinDays` (type: `integer`):

Keep only registered domains that expire within this many days, or have already expired. Domains without a published expiry date are skipped. Use 0 to turn this off.

## `includeDns` (type: `boolean`):

Also save the domain's MX records (where its email goes) and IP addresses.

## `includeSsl` (type: `boolean`):

For registered domains, read the SSL certificate the website presents: issuer, expiry date, days left and whether it is valid.

## `maxResults` (type: `integer`):

Stop after saving this many domains. Use 0 for no limit.

## `maxConcurrency` (type: `integer`):

How many domains to check at the same time for each registry. Every registry is also rate-limited separately, so a slow registry never holds up the others.

## Actor input object example

```json
{
  "domains": [
    "google.com",
    "vipps.no",
    "bbc.co.uk"
  ],
  "onlyStatus": "all",
  "expiringWithinDays": 0,
  "includeDns": true,
  "includeSsl": true,
  "maxResults": 0,
  "maxConcurrency": 10
}
```

# Actor output Schema

## `domains` (type: `string`):

One item per domain with its registration data, status, DNS and SSL certificate.

## `runSummary` (type: `string`):

How many domains were checked, saved and filtered out, counts per status, skipped input and domains that could not be checked.

# 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": [
        "google.com",
        "vipps.no",
        "bbc.co.uk"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("vindr/bulk-whois-lookup").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": [
        "google.com",
        "vipps.no",
        "bbc.co.uk",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("vindr/bulk-whois-lookup").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": [
    "google.com",
    "vipps.no",
    "bbc.co.uk"
  ]
}' |
apify call vindr/bulk-whois-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,vindr/bulk-whois-lookup"
        }
    }
}
```

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/9YGMynNZ6DMEM1L3G/builds/hgl60ndtRZfORb1b0/openapi.json
