# Bulk DNS AAAA Record Checker (`automation-lab/bulk-dns-aaaa-record-checker`) Actor

Check IPv6 AAAA records for up to 5,000 domains and export addresses, TTLs, lookup status, DNS errors, and timestamps for IPv6-readiness audits.

- **URL**: https://apify.com/automation-lab/bulk-dns-aaaa-record-checker.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.58 / 1,000 domain extracteds

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?

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

## Bulk DNS AAAA Record Checker

Run a **bulk DNS lookup** focused on IPv6 AAAA records.
Supply domains or website URLs and receive one normalized row per unique hostname with returned IPv6 addresses, TTL values, lookup status, DNS errors, timing, and a check timestamp.

Use the Actor for recurring IPv6-readiness reviews, domain inventory audits, migration checks, and DNS snapshot exports.
It performs DNS queries directly; it does not crawl websites or require a proxy.

### What does Bulk DNS AAAA Record Checker do?

The Actor:

- accepts 1 to 5,000 domains or website URLs;
- extracts and normalizes each hostname;
- converts internationalized names to ASCII DNS form;
- removes duplicate hostnames within the run;
- resolves only IPv6 `AAAA` records;
- preserves the TTL returned for each answer;
- exports explicit success, no-record, missing-domain, and resolver-error states;
- records when each check completed and how long it took;
- supports bounded concurrency and DNS timeouts;
- optionally uses recursive DNS servers supplied by you.

A domain without an AAAA record still produces a row.
That makes negative results usable in an audit instead of silently dropping them.

### Who is this bulk DNS checker for?

**Infrastructure teams** can review whether production hostnames publish IPv6 addresses.

**Security and compliance teams** can preserve timestamped DNS evidence for an inventory.

**SaaS operations teams** can schedule the same domain portfolio and compare exported datasets downstream.

**Developers** can add normalized AAAA lookup results to deployment checks or asset pipelines.

**Consultants and agencies** can process client domain lists without checking hostnames one by one.

Choose this Actor when the job is specifically AAAA and IPv6 readiness.
Choose the related multi-record Actor when you also need A, MX, NS, TXT, CNAME, or SOA records.

### Why use a focused AAAA record checker?

Generic DNS tools often return many record families when the audit only needs IPv6 readiness.
This Actor keeps the input and output contract focused:

1. one charged output per unique hostname;
2. IPv6 addresses available as a simple string array;
3. address-and-TTL pairs retained for deeper analysis;
4. deterministic status values for filtering;
5. resolver errors preserved for diagnosis;
6. no browser, login, or residential proxy setup.

The result can be exported from Apify as JSON, JSONL, CSV, Excel, XML, or RSS where supported by the dataset API.

### Getting started

1. Open the Actor in Apify Console.
2. Add domains in the **Domains** field.
3. Keep concurrency at `20` for a normal portfolio.
4. Leave custom DNS servers empty unless you need a specific recursive resolver.
5. Click **Start**.
6. Open the default dataset when the run finishes.
7. Filter `lookupStatus` or `hasIpv6` to find gaps.
8. Export the dataset or connect it to the next step in your workflow.

A useful first input is:

```json
{
  "domains": [
    "google.com",
    "cloudflare.com",
    "github.com"
  ],
  "concurrency": 10
}
```

### Input parameters

| Field | Type | Default | Description |
| --- | --- | --- | --- |
| `domains` | string array | required | Domains or URLs to normalize and check. Maximum 5,000 entries. |
| `concurrency` | integer | `20` | Number of unique hostnames checked in parallel, from 1 to 100. |
| `timeoutMs` | integer | `5000` | DNS resolver timeout per attempt, from 500 to 30,000 milliseconds. |
| `dnsServers` | string array | runtime resolver | Optional IPv4 or IPv6 addresses of recursive DNS servers. |

URLs are accepted for convenience.
For example, `https://www.google.com/search?q=ipv6` is checked as `www.google.com`.
Trailing dots and hostname case are normalized.
Duplicate normalized hostnames produce only one result and one domain charge.

Inputs fail closed when a value is blank, malformed, not a public domain name, or outside a documented limit.

### Custom DNS resolver behavior

When `dnsServers` is omitted, the Actor first uses the runtime resolver.
A transient resolver failure receives one bounded attempt through the public Cloudflare and Google recursive resolvers.
Definitive `ENODATA` and `ENOTFOUND` responses are not retried as transient failures.

When you provide `dnsServers`, those servers are authoritative for the run.
The Actor does not fall back to public resolvers after a custom-resolver failure.
This supports reproducible internal resolver tests and organizations with a defined DNS policy.

Example:

```json
{
  "domains": ["cloudflare.com", "workers.dev"],
  "dnsServers": ["1.1.1.1", "2606:4700:4700::1111"],
  "timeoutMs": 4000,
  "concurrency": 5
}
```

### Output fields

Each unique normalized hostname creates one default-dataset row.

| Field | Meaning |
| --- | --- |
| `input` | Original domain or URL from the input list. |
| `hostname` | Normalized ASCII hostname queried. |
| `ipv6Addresses` | Sorted unique IPv6 address strings. |
| `records` | AAAA answer objects containing `address` and `ttl`. |
| `addressCount` | Number of unique returned IPv6 addresses. |
| `hasIpv6` | `true` when at least one AAAA address was returned. |
| `lookupStatus` | `success`, `no_record`, `not_found`, or `error`. |
| `errorCode` | Resolver code such as `ENODATA`, or `null` on success. |
| `errorMessage` | Resolver message, or `null` on success. |
| `checkedAt` | ISO 8601 completion timestamp. |
| `durationMs` | Lookup duration in milliseconds. |

### Example output

This representative record was produced by a local run against the final input contract:

```json
{
  "input": "cloudflare.com",
  "hostname": "cloudflare.com",
  "ipv6Addresses": [
    "2606:4700::6810:84e5",
    "2606:4700::6810:85e5"
  ],
  "records": [
    { "address": "2606:4700::6810:84e5", "ttl": 166 },
    { "address": "2606:4700::6810:85e5", "ttl": 166 }
  ],
  "addressCount": 2,
  "hasIpv6": true,
  "lookupStatus": "success",
  "errorCode": null,
  "errorMessage": null,
  "checkedAt": "2026-08-25T20:55:00.000Z",
  "durationMs": 28
}
```

DNS answers and TTLs change over time, so exact values will differ between runs.

### Understanding lookup status

`success` means at least one AAAA answer was returned.

`no_record` means the hostname resolved but no AAAA data was available, commonly reported as `ENODATA`.

`not_found` means the queried hostname did not exist according to the resolver, commonly `ENOTFOUND`.

`error` means the resolver could not produce a definitive answer because of a timeout, server failure, refusal, or another operational error.

Use both `lookupStatus` and the error fields.
A missing AAAA record is a valid audit result, while a resolver timeout usually deserves a retry or investigation.

### How much does it cost to check IPv6 AAAA records?

Pay-per-event pricing includes a **$0.001 run-start charge** and one **domain checked** event per unique normalized hostname.
The BRONZE domain price is **$0.00096 per domain**, with lower per-domain prices on higher Apify tiers.

BRONZE run examples use one start event plus one domain event for every unique hostname:

| Unique domains | Charge calculation |
| ---: | --- |
| 1 | one start event + 1 domain event |
| 10 | one start event + 10 domain events |
| 100 | one start event + 100 domain events |
| 1,000 | one start event + 1,000 domain events |

Duplicate inputs are not charged twice because they are resolved once.
Compute usage is handled by Apify under the applicable pay-per-event model.
Check the live pricing tab for the tier that applies to your account.

### Recurring IPv6-readiness workflow

A practical scheduled workflow is:

1. keep the approved domain inventory in Actor input or a Task;
2. schedule the Task daily, weekly, or monthly;
3. retain each run's default dataset;
4. compare `hostname`, `ipv6Addresses`, and `lookupStatus` downstream;
5. flag a transition from `success` to another state;
6. review TTL changes when migration timing matters;
7. send selected exceptions to a webhook, database, spreadsheet, or alerting system.

The Actor creates current snapshots.
It does not maintain history, compare prior runs, or send alerts by itself.

### Export and integration ideas

- Export CSV for an infrastructure inventory review.
- Send JSON rows to a data warehouse.
- Join `hostname` with ownership or application metadata.
- Filter `hasIpv6=false` for a migration backlog.
- Track `not_found` separately from `no_record`.
- Use `durationMs` to identify slow recursive resolver responses.
- Trigger a webhook after a scheduled Task completes.
- Feed IPv6 addresses into the related IP geolocation and network lookup Actor.

### Run through the Apify API with cURL

Replace `<APIFY_TOKEN>` with your Apify API token:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~bulk-dns-aaaa-record-checker/runs?token=<APIFY_TOKEN>&waitForFinish=300" \
  -H "Content-Type: application/json" \
  -d '{
    "domains": ["google.com", "cloudflare.com", "github.com"],
    "concurrency": 10
  }'
```

Read dataset items using the `defaultDatasetId` returned by the run response.
Avoid placing long-lived tokens in source control.

### Run through the Apify API with JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/bulk-dns-aaaa-record-checker').call({
    domains: ['google.com', 'cloudflare.com', 'github.com'],
    concurrency: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

Use environment variables or a secret manager for `APIFY_TOKEN`.

### Run through the Apify API with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/bulk-dns-aaaa-record-checker').call(
    run_input={
        'domains': ['google.com', 'cloudflare.com', 'github.com'],
        'concurrency': 10,
    }
)
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

The API output is the same typed dataset available in Console.

### Use with Apify MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/bulk-dns-aaaa-record-checker"
```

#### Claude Desktop, Cursor, and VS Code setup

Use this equivalent JSON configuration in Claude Desktop, Cursor, or VS Code:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/bulk-dns-aaaa-record-checker"
    }
  }
}
```

Example prompts:

- "Check AAAA records for these domains and summarize which are not IPv6 ready."
- "Run the bulk AAAA checker for my SaaS vendor list and return hostname, status, and addresses."
- "Export current IPv6 DNS records for this domain inventory so I can compare them next week."

### Performance tips

Keep the default concurrency for most internet-domain portfolios.
Increase it gradually only when the selected resolver tolerates more parallel queries.
Reduce concurrency when a custom resolver rate-limits requests.

Use a timeout long enough for the resolver and network path.
A very short timeout can turn slow but valid answers into operational errors.

Split unusually policy-sensitive portfolios by resolver requirements rather than mixing public and private DNS expectations.
The 5,000-input limit keeps runtime and accidental spend bounded.

### Limitations

DNS responses depend on resolver location, cache state, delegation, DNSSEC behavior, and query time.
The Actor reports the recursive answer it receives; it does not query every authoritative server independently.

TTL is the value returned by the recursive resolver and may reflect cache aging.
It is not guaranteed to equal the original authoritative TTL.

Only AAAA records are queried.
The Actor does not test HTTP connectivity over IPv6, TLS configuration, routing, firewall access, or application readiness.
Publishing an AAAA address is one readiness signal, not proof of end-to-end IPv6 service.

The Actor does not bypass split-horizon DNS.
Use your own reachable resolver when internal DNS views are required.

### Legality and responsible use

DNS record data is generally public infrastructure metadata, but domain inventories and internal resolver results may be sensitive.
Only submit lists you are authorized to process.
Protect API tokens and private resolver addresses.
Follow your organization's data retention and security policies when exporting datasets.

Do not use the Actor to misrepresent a complete security assessment.
Review applicable law, contracts, and platform policies for your workflow.

### Troubleshooting

**The run returns `no_record`.**
The resolver found no AAAA data for that hostname.
Verify the exact hostname and compare it with the intended web or service endpoint.

**The run returns `not_found`.**
The hostname did not exist from the selected resolver's view.
Check spelling, delegation, and whether a private resolver is required.

**The run returns `error`.**
Inspect `errorCode` and `errorMessage`.
Try a longer timeout, lower concurrency, or a known recursive resolver.

**The Actor rejects my input.**
Provide public domains or URLs rather than paths without a valid hostname, IP literals, blank values, or single-label internal names.
Custom DNS servers must be literal IPv4 or IPv6 addresses.

**Why did several inputs produce one row?**
Inputs that normalize to the same hostname are deduplicated within the run.

### Related Automation Lab Actors

- [Bulk DNS Record Lookup](https://apify.com/automation-lab/bulk-dns-lookup) resolves A, AAAA, MX, NS, TXT, CNAME, and SOA records when you need a broader DNS inventory.
- [IP Geolocation & Network Lookup](https://apify.com/automation-lab/ip-geolocation-network-lookup) enriches returned public IPv4 or IPv6 addresses with network and location context.

These are separate products with separate inputs and pricing.
Use Bulk DNS AAAA Record Checker for a focused per-domain IPv6 DNS audit.

### FAQ

#### Does the Actor verify that a website works over IPv6?

No.
It verifies published AAAA DNS answers only.
End-to-end readiness also requires routing, firewall, TLS, and application checks.

#### Does it return domains that have no AAAA record?

Yes.
Every valid unique hostname produces a row, including `no_record`, `not_found`, and `error` outcomes.

#### Can I use URLs instead of domains?

Yes.
The Actor extracts and normalizes each URL hostname before the DNS query.

#### Can I choose the DNS resolver?

Yes.
Provide one or more literal resolver IP addresses in `dnsServers`.

#### Does it monitor changes automatically?

The Actor creates a timestamped snapshot per run.
Use an Apify schedule and compare datasets in your own automation for monitoring or alerts.

#### Are duplicate domains charged more than once?

No.
Duplicate normalized hostnames are checked and charged once in a run.

#### What happens when one domain fails?

The Actor emits an error-state row and continues processing the remaining valid input portfolio.
Malformed input fails the run before lookups begin.

# Actor input Schema

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

Domains or website URLs to check. URLs are normalized to hostnames and duplicate domains are checked once.

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

Number of domains checked in parallel. Lower this when using a rate-limited custom resolver.

## `timeoutMs` (type: `integer`):

Timeout for each DNS resolver attempt.

## `dnsServers` (type: `array`):

Optional IPv4 or IPv6 recursive resolver addresses. Leave empty to use the runtime resolver with bounded public-resolver recovery for transient errors.

## Actor input object example

```json
{
  "domains": [
    "google.com",
    "cloudflare.com",
    "github.com"
  ],
  "concurrency": 20,
  "timeoutMs": 5000
}
```

# Actor output Schema

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

Dataset containing all domain AAAA lookup results.

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

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/bulk-dns-aaaa-record-checker").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",
        "cloudflare.com",
        "github.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/bulk-dns-aaaa-record-checker").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",
    "cloudflare.com",
    "github.com"
  ]
}' |
apify call automation-lab/bulk-dns-aaaa-record-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/bulk-dns-aaaa-record-checker"
        }
    }
}

```

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/tqhBOtaKkhez6SEXp/builds/bDEXoWWfKRnH1O3Ft/openapi.json
