# Domain Intel — DNS, WHOIS/RDAP, SSL & mail posture (`titian_troupe/domain-intel`) Actor

Bulk domain enrichment: A/AAAA/MX/NS/TXT records, registrar and domain age via RDAP, SSL certificate issuer and expiry, plus mail provider, SPF and DMARC detection. No API keys required.

- **URL**: https://apify.com/titian\_troupe/domain-intel.md
- **Developed by:** [Rumblingb](https://apify.com/titian_troupe) (community)
- **Categories:** Developer tools, Lead generation
- **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/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Domain Intel — DNS, WHOIS/RDAP, SSL & mail posture

Bulk domain enrichment in one pass: DNS records, registrar and domain age, SSL certificate
expiry, and mail posture (provider, SPF, DMARC).

No API keys. No WHOIS subscription. No per-lookup vendor cost.

### What you get per domain

| Group | Fields |
|---|---|
| **DNS** | `ipv4`, `ipv6`, `mx`, `nameservers`, `txt`, `cname`, `resolves` |
| **Mail** | `mailProvider`, `hasMx`, `spf`, `hasSpf`, `dmarc`, `hasDmarc` |
| **Registration** | `registrar`, `registered`, `expires`, `domainAgeDays`, `domainStatus` |
| **SSL** | `sslIssuer`, `sslValidTo`, `sslDaysRemaining`, `sslExpired`, `sslReachable` |

`mailProvider` is derived from MX records and identifies Google Workspace, Microsoft 365,
Zoho, Proton, Mimecast, Barracuda and Proofpoint, falling back to `Other / self-hosted`.

### Input

```json
{
  "domains": ["stripe.com", "https://www.github.com/features", "example.co.uk"],
  "includeSsl": true,
  "includeRdap": true,
  "maxConcurrency": 8
}
```

Full URLs are accepted and reduced to their hostname; a leading `www.` is stripped. Wire
`domains` to another Actor's output for bulk enrichment.

| Field | Default | Notes |
|---|---|---|
| `domains` | — | Required. |
| `includeSsl` | `true` | TLS handshake on 443 to read the certificate. Adds ~0.3–1s per domain. |
| `includeRdap` | `true` | Registrar and age lookup. Adds ~0.3–1s per domain. |
| `maxConcurrency` | 8 | Keep at or below 10 so RDAP does not rate-limit you. |

### Output

```json
{
  "domain": "stripe.com",
  "resolves": true,
  "ipv4": ["198.202.176.161", "198.137.150.161"],
  "mx": ["10 aspmx.l.google.com", "20 alt1.aspmx.l.google.com"],
  "hasMx": true,
  "mailProvider": "Google Workspace",
  "spf": "v=spf1 ip4:198.2.180.60/32 include:spf1.stripe.com ~all",
  "hasSpf": true,
  "dmarc": "v=DMARC1; p=reject; pct=100; rua=mailto:dmarc-reports@stripe.com;",
  "hasDmarc": true,
  "registrar": "SafeNames Ltd.",
  "registered": "1995-09-13T04:00:00Z",
  "domainAgeDays": 11278,
  "sslIssuer": "DigiCert Inc",
  "sslDaysRemaining": 106,
  "sslExpired": false
}
```

A `SUMMARY` record lands in the key-value store with run totals: how many resolve, how many
have MX/SPF/DMARC, and how many certificates are **expired or expiring within 30 days**.

There is a second dataset view, **SSL expiry watch**, that shows just the certificate columns.

### Typical uses

- **Lead qualification** — filter a prospect list to domains that actually resolve and accept mail
- **Email deliverability audits** — find prospects or clients with no SPF or no DMARC, which is a concrete thing to sell them
- **Certificate monitoring** — schedule it and alert on `sslDaysRemaining <= 30`
- **Tech-stack segmentation** — split a list by Google Workspace vs Microsoft 365
- **Domain due diligence** — `domainAgeDays` and `domainStatus` for fraud and acquisition checks

### Reliability note

DNS TXT resolution falls back to **DNS-over-HTTPS** whenever the platform resolver fails or
returns nothing. Some networks answer A and MX queries fine but silently time out on TXT,
which would otherwise make SPF and DMARC look absent when they are published. The fallback
runs over port 443 and sidesteps that entirely.

### Limits

RDAP coverage varies by TLD — a few ccTLDs do not operate an RDAP service, in which case
registrar and age come back `null` while everything else is unaffected. SSL fields require a
reachable host on port 443; `sslReachable: false` records the reason.

# Actor input Schema

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

Domains to inspect. Full URLs are accepted and reduced to their hostname, and a leading www. is stripped. Wire this to the output of another Actor for bulk enrichment.

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

Open a TLS connection on port 443 to read the certificate issuer, validity window and days remaining. Adds roughly 0.3-1s per domain.

## `includeRdap` (type: `boolean`):

Query rdap.org for registrar, registration date, domain age and expiry. RDAP is the IETF successor to WHOIS: free and keyless. Adds roughly 0.3-1s per domain.

## `sslTimeoutMs` (type: `integer`):

Per-domain TLS handshake timeout.

## `rdapTimeoutMs` (type: `integer`):

Per-domain RDAP request timeout.

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

How many domains to process in parallel. Keep at or below 10 so RDAP does not rate-limit you.

## Actor input object example

```json
{
  "domains": [
    "apify.com",
    "https://www.github.com/features",
    "stripe.com"
  ],
  "includeSsl": true,
  "includeRdap": true,
  "sslTimeoutMs": 8000,
  "rdapTimeoutMs": 10000,
  "maxConcurrency": 8
}
```

# 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",
        "https://www.github.com/features",
        "stripe.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("titian_troupe/domain-intel").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",
        "https://www.github.com/features",
        "stripe.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("titian_troupe/domain-intel").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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",
    "https://www.github.com/features",
    "stripe.com"
  ]
}' |
apify call titian_troupe/domain-intel --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=titian_troupe/domain-intel",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/hGhsAa5gdjglw1vbI/builds/G9ZkiGFcAV10ygg9r/openapi.json
