# DNS Routing Drift Feed (`f108/dns-routing-drift-feed`) Actor

Track public A, AAAA, MX, NS and CAA records with persistent snapshots and structured changes. Ignore TTL and ordering noise. Query a fixed public DNS API without contacting target hosts.

- **URL**: https://apify.com/f108/dns-routing-drift-feed.md
- **Developed by:** [Fumiya Hanzawa](https://apify.com/f108) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 domain checks

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

## DNS Routing Drift Feed

Capture selected public DNS routing records and compare them with persistent snapshots. Feed structured
changes into infrastructure inventories, scheduled audits and AI-agent workflows without visiting the target
website, contacting its mail servers or modifying DNS. This is not an uptime, email-deliverability or security certification tool.

### Input

```json
{"domains":["example.com"],"recordTypes":["MX","NS","CAA"],"stateKey":"routing-watch"}
```

Use 1–10 ASCII domain names (punycode is accepted). Schemes, paths, ports, IP literals and common private/
special-use suffixes are rejected. Public domains only; no secret or internal names. Types are restricted to
A, AAAA, MX, NS and CAA, at most five. Duplicate domains/types are checked once. Default is MX/NS/CAA.

### Output

One Dataset row per complete domain check: domain, checkedAt, status (baseline/unchanged/changed), records
by requested type and changes with before/after. First run is a baseline, not a change alert. Changing the
recordTypes set creates an independent baseline. CNAME answers returned with selected types are retained.
TTL, answer order, duplicate records, DNS diagnostic comments and unrelated record types are excluded from
comparison. Hostname case/trailing dots and IP notation are normalized. Other presentation-only changes
(such as alternative CAA quoting) may still appear as changes; no universal canonicalization is promised.

DNS NOERROR with no answers and NXDOMAIN (rcode=3) are valid billable observations. They are not mislabeled
as HTTP/network errors. SERVFAIL/REFUSED, truncation, malformed responses, question mismatches, redirects
and timeouts fail the run and preserve the previous snapshot. All requested types must complete before a
domain is billable. Processing stops on the first source error; earlier successful domains remain billable.
Up to 128 KB decoded response and 100 answer records per query, 20 seconds per domain, no automatic retry.

Only Google's public recursive DNS view is observed. Caching, geo-routing and propagation can produce
differences; this is neither authoritative-zone enumeration nor multi-resolver consensus. NXDOMAIN is an
observation, not proof that a registered domain is available. DNSSEC validation is left enabled at the resolver,
but this Actor does not certify a domain's DNSSEC/security posture. No zone transfers or subdomain discovery.

### Pricing

- **domain-check: $0.003** per complete domain check (all selected types, including unchanged/empty/NXDOMAIN).
- **apify-actor-start: $0.00005** per started GB, minimum one. Memory is fixed at 256 MB.
- No Dataset automatic event and no separate platform-usage surcharge. Post-run storage/export may have plan costs.

Set maximum charge in Console or API maxTotalChargeUsd. $0.00305 permits one domain plus start. Dataset is
saved before charging; the snapshot advances only after confirmed charge. Processing stops at the spending
limit. Failed queries have no domain-check charge but start still applies. A limit is per run, not per account.
Storage, charge and snapshot update are not atomic. Interrupted runs may leave saved uncharged output or
charged output without updated state. Resurrection/replay of an old run is rejected; a new run is billable.

### State, scheduling and deletion

Do not run the same stateKey concurrently in one account. Serialize schedules and integrations; use separate
keys for independent watches. No distributed lock or automatic schedule is installed. Start with daily checks.
Named KVS `dns-routing-<stateKey>` retains normalized records until you delete it; each domain/types set uses
one hashed key. Dataset retains diffs; default KVS retains INPUT/OUTPUT, replay marker and last charge.
Unnamed storage follows your plan retention; named data does not automatically expire. Review retention at
least every 30 days. Stop schedules and runs before deleting the named KVS, each related Dataset/default KVS,
obsolete run logs and downstream exports. Next run establishes a baseline. Deleting one store does not remove
other data copies. Authenticated DELETE /v2/key-value-stores/{id} and /v2/datasets/{id} can automate your policy.
Keep storage access restricted; do not share tokens. Do not resurrect old runs after deleting replay markers.

### Privacy and source policy

Domains and record types are sent to **Google Public DNS** via https://dns.google/resolve. The client supplies
edns\_client\_subnet=0.0.0.0/0 to avoid forwarding a client subnet to authoritative servers. Google can still
observe the request and platform IP; this is not anonymous or private DNS. Do not submit personal, confidential
or internal names. Only DNS routing records are retained, not WHOIS contacts, TXT tokens, SPF/DMARC or email
addresses. No data is sent to an LLM. Returned record targets are data only and are never fetched or connected to.

All outgoing HTTP requests use a fixed Google HTTPS endpoint, certificate validation, no redirects and no
environment proxy. Input cannot select an API host. Login, CAPTCHA, access-control bypass, mail delivery,
port scanning and changing DNS records are unsupported. Users must confirm rights and source terms and
avoid abusive frequency. Public DNS is not a license to republish confidential information; we do not claim
automated legal/robots compliance. Normal valid public-domain checks need no operator intervention.

[Official Google DNS JSON API](https://developers.google.com/speed/public-dns/docs/doh/json)
This is an independent tool, not affiliated with Google. No Google account, API key, paid plan or LLM is needed.

### API / agents

Use the standard Apify run API with this input and retrieve the Dataset or OUTPUT via the output schema.
The finite input and structured delta are suitable for Apify Actor MCP tools; a separate custom MCP server is
not provided. Direct API execution is tested. A particular MCP client's workflow is not separately certified.

### Development

Python 3.12 / Apify SDK 4.0.2. Entry point: python -m dns\_drift. Offline tests are under third\_actor/tests.

# Actor input Schema

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

1–10 public ASCII domain names, no URLs or confidential/internal names. Sent to Google Public DNS.

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

Choose only A, AAAA, MX, NS or CAA. No TXT or WHOIS collection.

## `stateKey` (type: `string`):

Serialize runs sharing this key. Named snapshots persist until deleted.

## Actor input object example

```json
{
  "domains": [
    "example.com"
  ],
  "recordTypes": [
    "MX",
    "NS",
    "CAA"
  ],
  "stateKey": "default"
}
```

# Actor output Schema

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

No description

## `summary` (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": [
        "example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("f108/dns-routing-drift-feed").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"] }

# Run the Actor and wait for it to finish
run = client.actor("f108/dns-routing-drift-feed").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"
  ]
}' |
apify call f108/dns-routing-drift-feed --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,f108/dns-routing-drift-feed"
        }
    }
}
```

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/xhLqTyN1sUt2dZMFX/builds/6pqtVd7m0vRrojVZy/openapi.json
