# Domain & Email Infrastructure Analyzer (`vincesoft/domain-analyzer`) Actor

Bulk DNS, SPF, direct DMARC, supplied DKIM, RDAP and TLS evidence.

- **URL**: https://apify.com/vincesoft/domain-analyzer.md
- **Developed by:** [VinceSoft](https://apify.com/vincesoft) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$3.00 / 1,000 domain analysis results

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

## Domain & Email Infrastructure Analyzer

Bulk DNS, SPF, direct DMARC, supplied DKIM, RDAP and TLS evidence. Designed for operations teams and developers combining customer-supplied data with Apify workflows. Processing uses local rules and standard protocols, with no required paid API or browser.

### Use cases

- Audit a domain portfolio
- Investigate email configuration
- Prepare MSP monitoring baselines

### Features and input

Inline records, an Apify Dataset ID, CSV/TSV/JSON arrays/JSONL, uploaded KVS files, and public HTTPS files. Choose exactly one source. File format is inferred from the extension when omitted; UTF8 BOM is supported, UTF16/Latin1 require explicit encoding. Files stream or parse in bounded passes; datasets page500 items. At most1,000 fresh domain analyses per run. Set maxRecords (default10,000, hard100,000), maxFileBytes (default25MB, hard100MB). Exceeding a limit fails with retained partial results.

Focused defaults and optional controls are described in the Console input form. The Console and automatic-test input prefills example.com and bücher.de with optional RDAP/TLS disabled. An explicit empty API input still produces a successful empty run; supplying another source does not inject sample domains. CLI-only `localFile` accepts a file path; it is blocked in cloud runs and deliberately omitted from the public schema. File uploads use `keyValueStoreId` plus `fileKey`; request no more than one source.

```json
{
  "domains": [
    "example.com",
    "bücher.de"
  ],
  "rdap": false,
  "tls": false
}
```

### Outputs

Default Dataset has one result for every examined row, including invalid rows and duplicates. Each has schemaVersion, runId, processedAt, sourceRecordId (1-based input ordinal), valid and diagnostics. Diagnostics expose severity/code/field/message/suggestedFix/autoFixed/reference; raw values are intentionally omitted. Cleaner results contain cleaned and duplicate survivor linkage. Domain results contain protocol evidence and score reasons. `SUMMARY` in KVS reports totals, rule/field counts, duplicate counts, duration and fatalError. `CLEANED` contains valid first survivors only, as canonical JSONL or CSV (`outputFields` required). Invalid rows remain available for audit in the Dataset. PII output never contains original records.

Illustrative abbreviated output:

```json
{
  "schemaVersion": "1",
  "runId": "local-example",
  "processedAt": "2026-10-04T00:00:00Z",
  "sourceRecordId": "1",
  "valid": true,
  "diagnostics": [],
  "normalizedDomain": "example.com",
  "dns": {
    "MX": {
      "records": [
        "0 ."
      ],
      "ttl": 23,
      "status": "OK",
      "attempts": 1
    }
  }
}
```

### API and schedules

Call the Actor API using its ID; JSON body is the same input as Console. Replace placeholders and keep your token private:

```bash
curl -X POST "https://api.apify.com/v2/acts/NdXIEunchevh1tJet/runs" \
  -H "Authorization: Bearer $APIFY_TOKEN" -H "Content-Type: application/json" \
  --data-binary @example-input.json
```

Python SDK callers can use `await Actor.call('vincesoft/domain-analyzer', run_input=input)` from another Actor. Console tasks/schedules use the same saved input; retrieve the returned defaultDatasetId/defaultKeyValueStoreId. Upstream scrapers may supply a Dataset ID to this Actor; send cleaned exports to downstream analytics. Combine Domain Analyzer with Lead Cleaner, Product Cleaner with Feed Doctor, and PII Redactor before external AI workflows. No webhooks or email messages are sent by this code.

### Local usage

From monorepo root: `python -m pip install -e ".[dev]"`, set `APIFY_LOCAL_STORAGE_DIR` to a new absolute directory, put example input in `key_value_stores/default/INPUT.json`, then `python -m hermes.runtime domain`. This uses the real Apify SDK local lifecycle and storages. Local development requires the Hermes source repository. This Actor is available on Apify Store as vincesoft/domain-analyzer.

### Pricing and performance

Pay per event: $2.00/1,000 domain analysis results plus $0.005 per run start. Each examined input row delivered to the Dataset is billable, including cached duplicates and invalid-input diagnostics. No free per-run allowance, per-file fee or paid integration. Platform usage is included. The minimum run spending limit is $0.007 (start plus one result). The Actor stops before further network work when the remaining budget cannot cover another result; SUMMARY reports chargedResults and chargeLimitReached. Remove duplicate input domains before running to reduce charges. Private cloud validation on October 5, 2026 covered DNS, optional RDAP/TLS, mixed input and billing limits. Costs and margin depend on batch size, network latency and output size. Startup, storage writes and protocol waits dominate small batches. Memory is fixed at512MB; hard caps protect the deployment; cleaned upload is bounded100MB and total scratch disk250MB. No claim of processing millions of rows. Runs are restart-from-input, without migration resume guarantees.

### Privacy and security

Public downloads use HTTPS443, checked public IPv4/IPv6 and pinned connection addresses, revalidated redirects, identity encoding, bounded bytes/time and MIME allowlist. XML entities/DTD disabled; nesting, record length and concurrency capped. CSV exports escape formula-like cells. Logs contain counts and safe error codes only. Records stay in customer-controlled Apify storage; this project sends no analytics. Cleaner input/output may contain PII unless explicitly redacted. Hash action requires secret minimum16-character HMAC key; it produces pseudonyms, not guaranteed anonymization. Delete input and output storages under your retention policy. No universal compliance or safety certification.

### Limitations

No mailbox existence, SMTP probing, reputation/safety claims, recursive SPF budget evaluation or DMARC inheritance. DKIM requires supplied selectors. Provider inference is heuristic. RDAP is exact-name, registry availability varies. Invalid TLS certificates return unknown/error rather than unverified metadata. No disposable/parked datasets bundled.

All Actors omit arbitrary regex rules, XLSX, paid integrations, automatic ambiguity repair and migration checkpointing. Records that fail validation continue in permissive mode; strict stops at first invalid row. Source corruption, unsafe URLs and resource limits always fail. Output timestamps vary across runs; deterministic cleaned fields and diagnostic rules do not.

### Troubleshooting and FAQ

- **Why did my run fail?** Read KVS ERROR.code and SUMMARY.fatalError. Configuration failures can have only ERROR. Fix source format/limits rather than retrying blindly.
- **Why are rows missing from CLEANED?** Invalid and duplicate rows are retained in the Dataset but excluded from export. Check diagnostics and survivorSourceRecordId.
- **Can this verify real-world facts?** Only the documented static/protocol checks. It does not verify mailboxes, delivery addresses or Merchant Center approval.
- **Can I process a private URL?** No. Upload a file to Apify KVS or supply a Dataset instead.
- **Can I merge duplicate values?** No; first survivor wins. Review linked duplicate rows before manual merging.
- **Can I monitor changes?** Schedule runs in Apify; compare datasets in your own workflow. Built-in historical diff/alerts are future work.

# Actor input Schema

## `records` (type: `array`):

Small inline batch; choose exactly one input source.

## `datasetId` (type: `string`):

Customer-accessible Dataset; read in pages of 500.

## `keyValueStoreId` (type: `string`):

Apify KVS containing the uploaded file; uses APIFY_TOKEN if set.

## `fileKey` (type: `string`):

Record key in the specified KVS.

## `fileUrl` (type: `string`):

Only public HTTPS port 443; pinned IPs; no compressed responses.

## `format` (type: `string`):

If omitted infer from file extension, otherwise JSONL.

## `encoding` (type: `string`):

UTF8 BOM automatically accepted; other encodings must be explicit.

## `delimiter` (type: `string`):

Exactly one character; CSV defaults comma, TSV tab.

## `headers` (type: `array`):

Explicit ordered fields for headerless CSV/TSV input.

## `maxRecords` (type: `integer`):

Exceeding limit fails explicitly with partial outputs retained.

## `maxFileBytes` (type: `integer`):

Uncompressed bounded files; archive/XLSX rejected.

## `strict` (type: `boolean`):

Stop after first invalid output; source-level errors always fail.

## `timeoutSeconds` (type: `integer`):

Per DNS query or network socket timeout; bounded download deadline.

## `retries` (type: `integer`):

Only bounded read operations retry; never retry a Dataset write in engine.

## `outputFormat` (type: `string`):

JSONL or formula-escaped CSV; only valid survivors exported.

## `outputFields` (type: `array`):

Required ordered fields when outputFormat is csv.

## `domain` (type: `string`):

Domain or http(s) URL; IDNs converted to punycode.

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

Bulk domain strings; alternative to records with domain fields.

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

At most16 DNS requests in flight; records queried sequentially per worker.

## `rdap` (type: `boolean`):

Off by default; IANA bootstrap, at most1 request start/second; no contact data export.

## `tls` (type: `boolean`):

Off by default; public IP pinned socket, hostname verification.

## `dkimSelectors` (type: `array`):

Only supplied selectors, max10; no guessing.

## `dnsResolvers` (type: `array`):

Optional public IPv4/IPv6 DNS servers, max3.

## Actor input object example

```json
{
  "fileKey": "INPUT_FILE",
  "encoding": "utf-8-sig",
  "maxRecords": 10000,
  "maxFileBytes": 25000000,
  "strict": false,
  "timeoutSeconds": 5,
  "retries": 1,
  "outputFormat": "jsonl",
  "domains": [
    "example.com",
    "bücher.de"
  ],
  "concurrency": 4,
  "rdap": false,
  "tls": false
}
```

# Actor output Schema

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

DNS and email infrastructure evidence for each input row, including diagnostics and cached duplicates.

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

Record counts, diagnostics by rule, billing counts and spending-limit status.

## `cleaned` (type: `string`):

Valid first-survivor results exported as JSONL or the selected CSV format.

# 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": [
        "example.com",
        "bücher.de"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("vincesoft/domain-analyzer").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": [
        "example.com",
        "bücher.de",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("vincesoft/domain-analyzer").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": [
    "example.com",
    "bücher.de"
  ]
}' |
apify call vincesoft/domain-analyzer --silent --output-dataset

```

## MCP server setup

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

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/NdXIEunchevh1tJet/builds/Ml4DdfZKvB5kgxYBj/openapi.json
