# Dns Records Lookup Doh (`b2b_lead_generation/dns-records-lookup-doh`) Actor

Extract A, MX, TXT, NS, and other public DNS records for domains using Google Public DNS or Cloudflare over HTTPS. Results can be exported directly as JSON, CSV, or Excel datasets.

- **URL**: https://apify.com/b2b_lead_generation/dns-records-lookup-doh.md
- **Developed by:** [B2B Lead Generation](https://apify.com/b2b_lead_generation) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.99 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

### DNS Records Lookup (DoH)

<p align="center">
  <img src="https://imgur.com/P59ksIp.png" alt="DNS Records Lookup" style="max-width:100%; border-radius:14px; width:680px;" />
</p>

DNS records lookup for anyone who needs A, MX, TXT, NS, and other public zone records in bulk. The actor processes DNS queries smoothly over HTTPS, one request at a time, and saves structured results to a dataset you can easily export as JSON, CSV, or Excel.

### Use Cases

- **Mail Setup**: Confirm MX hosts and check whether TXT records contain active SPF policies.
- **SPF and DMARC Audits**: Validate domain TXT records and `_dmarc` entries in a single run.
- **Migration Checks**: Compare A and NS responses across a list of domains prior to a DNS cutover.
- **Monitoring**: Schedule periodic runs on domain lists to track and diff record changes over time.
- **Data Integration**: Import structured DNS data straight into Google Sheets or data warehouses.

### What Data Does This Actor Extract?

In **Lookup mode**, the actor processes each domain and requested record type.

In **SPF/DMARC mode**, it evaluates TXT records for the domain alongside `_dmarc.<domain>`. Rows containing `v=spf1` or `v=DMARC1` are parsed for additional details like `authKind` and `policyToken` (`~all`, `-all`, or DMARC `p=` values).

Empty answers or non-existent domains (`NXDOMAIN`) are logged and skipped to keep your output clean. Any bad inputs or network failures are captured as clean error rows with diagnostic messages. Duplicate record rows from the same run are automatically deduplicated.

### Input

| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `mode` | string | `lookup` | Select `lookup` for bulk DNS records, or `SPF/DMARC check`. |
| `domains` | array | `["example.com"]` | List of domain names to process. |
| `recordTypes` | array | `["A", "MX", "TXT", "NS"]` | Supported types: A, AAAA, MX, TXT, NS, CNAME, SOA, CAA. |
| `resolver` | string | `google` | Choose your preferred DNS-over-HTTPS provider (`google` or `cloudflare`). |
| `maxItems` | integer | `100` | Row cap per run (maximum 1,000). |
| `requestDelaySecs` | integer | `1` | Pause between queries in seconds. |
| `userAgent` | string | `B2BLeadGenerationResearch/1.0` | Custom user agent string. |
| `timeoutSecs` | integer | `300` | Total run timeout in seconds. |
| `requestTimeoutSecs` | integer | `30` | Per-request timeout in seconds. |
| `proxyConfiguration` | object | No proxy | Optional proxy configuration if needed. |

#### Example Input

```json
{
  "mode": "lookup",
  "domains": ["example.com", "google.com"],
  "recordTypes": ["A", "MX", "TXT", "NS"],
  "resolver": "google",
  "maxItems": 100,
  "requestDelaySecs": 1,
  "userAgent": "B2BLeadGenerationResearch/1.0 (contact: research@b2bleadgeneration.com)",
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": { "useApifyProxy": false }
}

```

### Output

```json
{
  "domain": "example.com",
  "recordType": "MX",
  "status": 0,
  "name": "example.com.",
  "rrType": 15,
  "ttl": 129,
  "data": "0 .",
  "resolver": "google",
  "scrapedAt": "2026-10-12T00:00:00+00:00"
}

```

| Field | Type | Description |
| --- | --- | --- |
| `domain` | string | Domain name from the input. |
| `recordType` | string | Requested DNS record type. |
| `status` | integer | Response status code. |
| `name` | string | Owner name returned in the answer. |
| `rrType` | integer | Numeric DNS type code (e.g., 1 for A, 15 for MX, 16 for TXT). |
| `ttl` | integer | Time to live in seconds. |
| `data` | string | Record payload or value. |
| `resolver` | string | Selected provider (`google` or `cloudflare`). |
| `scrapedAt` | string | UTC timestamp of the lookup. |
| `authKind` | string | Set to `spf`, `dmarc`, or `txt` during SPF/DMARC analysis. |
| `policyToken` | string | Parsed SPF mechanism or DMARC policy setting. |
| `error` | string | Present if the request encountered an error. |
| `message` | string | Detailed reason for any failed entry. |

Dataset views include **Overview** and **Errors**.

### How It Works

1. Parses your configuration, domain list, and row limits.
2. Builds query tasks for each domain and requested record type (or TXT & `_dmarc` in SPF/DMARC mode).
3. Sends query requests formatted for the target DNS-over-HTTPS service.
4. Respects `requestDelaySecs` and applies standard backoff retry logic on temporary network issues.
5. Maps response answers into clean rows, drops duplicates, and stops once `maxItems` is reached.

### FAQ

**Which record types can I request?**

A, AAAA, MX, TXT, NS, CNAME, SOA, and CAA.

**What happens if a domain name does not exist?**

Empty or `NXDOMAIN` answers produce no dataset rows. The log simply notes the empty query so your dataset stays clean.

**Can I check SPF and DMARC without specifying TXT manually?**

Yes. Switch the `mode` to **SPF/DMARC check**, and the actor automatically looks up TXT records for both the main domain and `_dmarc.<domain>`.

**Does it follow truncated (TC) responses over TCP?**

No. If a response is flagged as truncated, the actor retains all records present in that response without opening additional connections.

### Trademark Notice

DNS Records, Google, Cloudflare, and related names, logos, and trademarks belong to their respective owners. Their mention in this documentation is solely to identify compatibility and source context and does not imply affiliation, sponsorship, or endorsement.

### Is Web Scraping Legal?

This tool collects publicly accessible DNS data available on open networks. Public data collection is widely practiced, but how you handle, store, or re-publish the data matters. Always respect applicable data privacy practices and usage guidelines.

For more information on best practices, check out Apify's guide on web scraping legality.

This is not legal advice. To learn more, read Apify's guide: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

# Actor input Schema

## `mode` (type: `string`):

Bulk DNS lookup queries each domain and record type. SPF/DMARC check queries TXT on the domain and on \_dmarc.domain, then labels v=spf1 and v=DMARC1 rows.

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

Domain names to resolve, one per line. International names are converted to punycode before the query.

## `recordTypes` (type: `array`):

DNS record types for Bulk DNS lookup. Allowed values: A, AAAA, MX, TXT, NS, CNAME, SOA, CAA. Ignored in SPF/DMARC check mode.

## `resolver` (type: `string`):

Public DNS-over-HTTPS resolver. Google uses dns.google/resolve. Cloudflare uses cloudflare-dns.com/dns-query with Accept application/dns-json.

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

Maximum dataset rows for this run, including error rows. Default 100. Hard maximum 1000.

## `requestDelaySecs` (type: `integer`):

Seconds to wait between DNS queries. Default 1. Use 0 only for a short list.

## `userAgent` (type: `string`):

User-Agent sent on every DNS-over-HTTPS request. Include a contact address so the resolver operator can reach you.

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

Stop the run after this many seconds and keep rows already collected. Default 300. Maximum 3600.

## `requestTimeoutSecs` (type: `integer`):

Per-request timeout for Google and Cloudflare DNS-over-HTTPS. Default 30.

## `proxyConfiguration` (type: `object`):

Optional proxy for DNS-over-HTTPS requests. Default is no proxy. These resolvers are public. Turn on Apify Proxy only if a resolver blocks the run IP.

## Actor input object example

```json
{
  "mode": "lookup",
  "domains": [
    "google.com",
    "example.com"
  ],
  "recordTypes": [
    "A",
    "MX",
    "TXT",
    "NS"
  ],
  "resolver": "google",
  "maxItems": 100,
  "requestDelaySecs": 1,
  "userAgent": "BigiByteActorResearch/1.0 (contact: research@bigibyte.com)",
  "timeoutSecs": 300,
  "requestTimeoutSecs": 30,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `records` (type: `string`):

Domain, record type, DNS status, owner name, TTL, and record data.

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

Queries that failed, with the error code, URL, and HTTP status.

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

Every row from the run, without a table view applied.

# 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",
        "example.com"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("b2b_lead_generation/dns-records-lookup-doh").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",
        "example.com",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("b2b_lead_generation/dns-records-lookup-doh").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",
    "example.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call b2b_lead_generation/dns-records-lookup-doh --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,b2b_lead_generation/dns-records-lookup-doh"
        }
    }
}
```

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/Grfl5dIZg5Yqh5giP/builds/G77tHgIeoFmimEHzK/openapi.json
