# WHOIS & DNS Lookup $1.5/1K | Domain Registration & DNS Records (`apivault_labs/domain-intelligence-scraper`) Actor

Run bulk WHOIS/RDAP and typed DNS lookups with certificate and HTTP signals; partial coverage stays explicit. Bulk export: JSON, CSV, Excel and API. PPE: $1.5/1K domain results; start fee, usage extra.

- **URL**: https://apify.com/apivault_labs/domain-intelligence-scraper.md
- **Developed by:** [Apivault Labs](https://apify.com/apivault_labs) (community)
- **Categories:** Developer tools, Business, Marketing
- **Features:** Limited permissions
- **Stats:** 8 total users, 3 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 domain analyzeds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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

## WHOIS & DNS Lookup | Bulk Domain Intel

Analyze a public domain portfolio with RDAP registration data, seven typed DNS lookups, certificate transparency observations, passive subdomain names and HTTP response headers. No third-party API key is needed. An Apify account/token is required for API and MCP access.

### First run

```json
{"domains": ["apify.com", "github.com"], "timeout": 15}
```

Download useful observations as JSON, CSV or Excel from the Dataset. Open `SUMMARY` for coverage and spending limits, and `ERRORS` for failed sources. Each row has `domain`, `checkedAt`, `success`, `status` (`complete` or `partial`) and `sourceStatus`. A run can succeed with partial source coverage; inspect these fields before using a result.

### Portfolio workflow

For checking registration expiry and mail/DNS setup, use:

```json
{"domains": ["apify.com", "github.com"], "extractWhois": true, "extractDns": true, "extractSsl": false, "extractSubdomains": false, "extractHttp": false}
```

Use `whois.expirationDate` for a reported registration expiry, `dns.mx` for observed mail records and `dns.txt` for published text records. Registrant names often remain unavailable or redacted. Mail records do not prove use of a particular paid email service.

### Inputs

| Field | Default | Meaning |
| --- | --- | --- |
| `domains` | required | 1–1000 hostname or HTTP(S) URL strings. IDNs become ASCII. Exact normalized hostnames are deduplicated; www and subdomains are preserved. Credentials, IP literals, local names and nonstandard ports are unsupported. Invalid entries are counted in SUMMARY. |
| `extractWhois` | true | RDAP registrar, dates, nameservers, status and publicly disclosed registrant. Subdomains may have no RDAP domain object; no silent parent-domain substitution. |
| `extractDns` | true | A, AAAA, MX, NS, TXT, CNAME, CAA through public DoH; Cloudflare with Google fallback. |
| `extractSsl` | true | Summary of crt.sh matching certificate transparency entries. |
| `extractSubdomains` | true | Passive names observed in the same crt.sh response. |
| `extractHttp` | true | HTTPS HEAD response and headers, following at most five redirects to public HTTP(S) hosts. No HTTP fallback on TLS failure. |
| `maxConcurrency` | 5 | 1–20 simultaneous domain analyses. Lower this for public-source rate limits. |
| `timeout` | 15 | 5–60 seconds per source request; DNS fallback may take additional requests. |
| `maxSubdomains` | 100 | 1–1000 returned names per domain; observed count and truncation are explicit. |

Select at least one extraction flag. Requests larger than 1000 entries must be split into batches. There is no hidden pagination or complete-zone promise.

### Result interpretation

- `whois`: matched RDAP domain object. Missing registrant/registrar/date fields are null. RDAP errors including HTTP 404 stay explicit; they do not prove a domain is available to register.
- `dns`: lowercase record arrays. Only answers of the requested type appear in that array, so CNAME targets never become IP addresses. `records` retains answer name/type/TTL/data. `queryStatus` distinguishes `NOERROR` (including a valid empty record set) from `NXDOMAIN`. Unavailable lookups are null with `errors`. Public recursive DNS is not an authoritative zone export.
- `ssl`: `certCount` counts unique returned crt.sh entry IDs for the `%.domain` query. `latest*` refers to the most recent observed `not_before`. This is not the current endpoint TLS certificate, chain validation, a complete history, or a reliable live expiry alert. Large responses over 8 MiB return `RESPONSE_TOO_LARGE` instead of fabricated completeness.
- `subdomains`: sorted unique names under the requested hostname, excluding the apex and wildcard prefix. `subdomainCount` counts returned names; `subdomainsObservedCount` counts names in this response; `subdomainsTruncated` reports the output cap. This is passive and incomplete, with no proof of liveness or ownership.
- `http`: actual status and response headers. An HTTP 403/404 is an observed response, not a successful site audit. Header/CDN signals do not prove the full technology stack. Missing headers are null.

A failed source is null and listed in `errors` and `sourceStatus`. A domain for which every selected source fails is recorded only in `ERRORS`, with no Domain Analyzed event. Do not equate a missing observation with an empty source result. Public services may timeout or rate limit; rerun affected domains later.

### Pricing and spending

The current Domain Analyzed event is **$0.0015 per useful delivered domain observation ($1.50 per 1000)**. Partial observations and valid negative/empty DNS responses count as useful rows. All selected lookups share that one row fee; no fee is charged per subdomain or DNS record. The Actor Start event is $0.00005 per GB (minimum one event), and Apify platform usage is paid by the user. Your plan's effective pricing and platform usage are shown on the run.

Set `maxTotalChargeUsd` on the Apify run API to bound event charges. The SDK accounts for startup and delivered rows; `SUMMARY.budgetLimited` and `domainsNotAttempted` explain a stopped batch. Platform usage remains a separate cost. Failed source requests may still consume platform resources even when no row fee is charged.

### REST API

Keep your Apify token in an environment variable, never in a shared input or URL:

```bash
curl -X POST 'https://api.apify.com/v2/acts/apivault_labs~domain-intelligence-scraper/runs?build=latest&memory=256&timeout=600&maxTotalChargeUsd=0.05' \
  -H "Authorization: Bearer $APIFY_TOKEN" -H 'Content-Type: application/json' \
  -d '{"domains":["apify.com"],"extractSsl":false,"extractSubdomains":false}'
```

Poll `/v2/actor-runs/{runId}` until terminal status. Read `/v2/datasets/{defaultDatasetId}/items?clean=true` (add `format=csv` for CSV), and `/v2/key-value-stores/{defaultKeyValueStoreId}/records/SUMMARY` and `/records/ERRORS`. Source failures are explicit even if the run status is SUCCEEDED.

### MCP

Connect an authenticated client to `https://mcp.apify.com/?tools=apivault_labs/domain-intelligence-scraper`. Discover `apivault_labs--domain-intelligence-scraper` with `tools/list`, then call it with the same input plus `waitSecs: 30`. Use returned run/storage IDs with `get-dataset-items` and `get-key-value-store-record`. For a strict event spending cap, start the REST run with `maxTotalChargeUsd`.

### Scope and reliability

Public RDAP, recursive DNS and crt.sh availability vary by domain/TLD and time. WHOIS privacy, subdomain RDAP failures, public-source rate limits and unavailable CT responses are expected limitations, reported without invented values. This Actor does not scan ports, infer company size, guarantee domain availability, track changes between runs, or validate live TLS certificates. To compare portfolios over time, retain dated datasets and compare matching domains outside the Actor.

### Domain portfolio research: choose the evidence you need

This bulk WHOIS and DNS lookup is useful for domain operations, agency account
reviews and infrastructure research. Supply a known list of hostnames rather
than a keyword or industry: the Actor enriches those domains, not a prospecting
database. A registrar/date observation, typed DNS answers and HTTP headers can
help an analyst decide what to investigate next without manually opening each
public lookup service.

| Research goal | Select | What the result supports |
| --- | --- | --- |
| Registration review | RDAP | Reported registrar and dates, subject to disclosure |
| Mail-routing inventory | DNS | Published MX and TXT evidence, not inbox validation |
| Hosting/header review | DNS and HTTP | Resolved records and observed HTTPS headers |
| Passive namespace research | CT and subdomains | Names in returned transparency observations |
| Periodic portfolio comparison | Repeated runs and external diff | Changes between your dated observations |

#### Collect only DNS evidence

Use a narrow configuration when certificate transparency and registration data
are irrelevant. Disabling sources reduces the number of external requests, but
does not change the per-domain row rate. A valid empty DNS answer is still an
observation; distinguish it from an unavailable query using `queryStatus`.

```json
{
  "domains": [
    "apify.com"
  ],
  "extractWhois": false,
  "extractDns": true,
  "extractSsl": false,
  "extractSubdomains": false,
  "extractHttp": false,
  "maxConcurrency": 1
}
```

#### Review public web response headers

This configuration checks a known hostname's HTTPS response. Keep the final
response status with any server or security-header observation. A redirect or
403 can explain why a browser-facing site behaves differently from a DNS-only
inventory. Missing security headers alone are not a vulnerability assessment.

```json
{
  "domains": [
    "apify.com"
  ],
  "extractWhois": false,
  "extractDns": false,
  "extractSsl": false,
  "extractSubdomains": false,
  "extractHttp": true,
  "timeout": 15
}
```

#### Bound passive subdomain output

Use a small output cap for exploration. `maxSubdomains` controls returned names,
not the total size of an organization's infrastructure or a scan of those hosts.
Read the observed count and truncation flag before reporting coverage.

```json
{
  "domains": [
    "apify.com"
  ],
  "extractWhois": false,
  "extractDns": false,
  "extractSsl": true,
  "extractSubdomains": true,
  "extractHttp": false,
  "maxSubdomains": 10,
  "maxConcurrency": 1
}
```

### Export and compare domain observations

Keep `domain`, `checkedAt`, `status`, `sourceStatus` and the selected source fields
together in your exported data. JSON retains DNS record arrays and source-level
diagnostics; a CSV workflow should explicitly select or flatten nested fields.
Retain the original Dataset ID before starting another run so a report can be
reproduced from stored results rather than a later lookup.

For change review, join dated exports by normalized hostname and compare the
specific record type. Public recursive caches, source outages and redaction can
produce differences without a real infrastructure change. Recheck unexpected
observations before taking operational action. This Actor has no persistent
baseline, alert delivery, authoritative zone transfer or automatic renewal.

### Cost planning and questions

Ten delivered domain rows cost $0.015 in Domain Analyzed events, plus the start
event and user-paid platform usage. Ten domains with several selected sources
still produce at most one useful observation row per domain in that run. A
partial row is chargeable because it contains an actual observation; inspect
coverage rather than interpreting a paid row as all sources having succeeded.

**Can I find a domain owner's personal contact details?** Only data disclosed
by the public registration source can appear. Privacy-redacted registration
records remain redacted; this is not a contact database or a privacy bypass.

**Does an RDAP 404 mean a domain is free?** No. Source errors and unsupported
objects do not establish registration availability. Use a registrar's current
registration check for that decision.

**Why are www and apex results different?** The requested hostname is preserved.
DNS and HTTP can differ by hostname; a subdomain may lack its own RDAP object.
Submit the apex separately if you also need its registration observation.

**Should I retry the whole portfolio?** Inspect ERRORS and sourceStatus first.
Retry affected hosts later with a smaller scope or concurrency. Repeating good
rows creates another paid observation and does not repair historical results.

### n8n and developer integrations

Use this Actor in your automation or application with the existing community integrations below. An Apify account and API token are required; Actor and platform charges follow the [current pricing](https://apify.com/apivault_labs/domain-intelligence-scraper/pricing).

- **n8n community node:** [n8n-nodes-apivault-domain-intel](https://www.npmjs.com/package/n8n-nodes-apivault-domain-intel). Install package name `n8n-nodes-apivault-domain-intel` in a self-hosted n8n instance that permits community packages.
- **Python client and examples:** [GitHub](https://github.com/apivault-labs/apivault-labs/tree/main/python-clients/apivault-domain-intelligence-scraper).
- **n8n source and usage:** [GitHub](https://github.com/apivault-labs/apivault-labs/tree/main/community-nodes/n8n-nodes-apivault-domain-intel).

These are community packages. Publication on npm does not establish n8n verification or availability in n8n Cloud. Review the linked package README for supported inputs and setup.

# Actor input Schema

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

Public hostnames or HTTP(S) URLs, including IDN. Hostnames are preserved: www and subdomains are not silently removed. Invalid entries are counted; duplicates after normalization are processed once.

## `extractWhois` (type: `boolean`):

Registrar, creation date, expiration, owner (RDAP)

## `extractDns` (type: `boolean`):

A, AAAA, MX, NS, TXT, CNAME records via DNS-over-HTTPS

## `extractSsl` (type: `boolean`):

Certificate transparency observations from crt.sh; not a live TLS certificate or complete certificate history.

## `extractSubdomains` (type: `boolean`):

Passive names in crt.sh observations. Incomplete discovery; no liveness or company-size inference.

## `extractHttp` (type: `boolean`):

Fetch https://domain/ and record response headers (server, security headers, redirects)

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

Parallel domain lookups (default: 5)

## `timeout` (type: `integer`):

Timeout per individual API call

## `maxSubdomains` (type: `integer`):

Output cap; observed count and truncation are reported.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "github.com"
  ],
  "extractWhois": true,
  "extractDns": true,
  "extractSsl": true,
  "extractSubdomains": true,
  "extractHttp": true,
  "maxConcurrency": 5,
  "timeout": 15,
  "maxSubdomains": 100
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

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

No description

## `errors` (type: `string`):

No description

# 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",
        "github.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("apivault_labs/domain-intelligence-scraper").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",
        "github.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("apivault_labs/domain-intelligence-scraper").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",
    "github.com"
  ]
}' |
apify call apivault_labs/domain-intelligence-scraper --silent --output-dataset

```

## MCP server setup

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

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/ruSZXZxIolTyGCeqQ/builds/elmIiqHOAl3QD3QSe/openapi.json
