DNS Record Lookup — A, MX, TXT, NS, CNAME, SOA API
Pricing
from $2.40 / 1,000 successful lookups
DNS Record Lookup — A, MX, TXT, NS, CNAME, SOA API
Look up DNS records for any domain — A, AAAA, MX, TXT, NS, CNAME, or SOA — straight from Cloudflare's public DNS-over-HTTPS resolver, with DNSSEC validation status per record. Paste domains, press Start. Charged once per domain that resolves — NXDOMAIN and empty responses cost nothing.
Pricing
from $2.40 / 1,000 successful lookups
Rating
0.0
(0)
Developer
Adrian Voss
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
DNS Record Lookup
You give this actor a list of domains, and it queries their live DNS records — A,
AAAA, MX, TXT, NS, CNAME, or SOA — straight from
Cloudflare's public DNS-over-HTTPS resolver,
the same infrastructure behind 1.1.1.1. No API key, no scraping, no zone
transfer — just the answer a DNS resolver already gives out publicly, returned
as one flat row per domain (or one row per record, if you want it that way).
Who it's for
The accountable_eel catalogue sells company intelligence columns for outbound. Each actor takes a list of domains or company identifiers and returns one flat, stably-named row per input — firmographics, registry IDs, tech stack, email route, hiring activity — the shape a Clay table, an n8n workflow, or an AI agent can consume without post-processing. Pricing is pay-per-event and per-domain: a few tenths of a cent for a row that was actually found, and nothing for a miss, so a list that doesn't enrich costs you next to nothing. Where an official source exists — VIES, GLEIF, SEC EDGAR, Brønnøysund, PRH, RDAP — it is queried directly instead of scraped. No seat licence, no monthly minimum, no credit system to decode.
For DNS specifically, that means you paste a list of domains and get back what each one's nameservers are actually publishing right now — mail routing, IP addresses, TXT-record policy, DNSSEC status — without opening a terminal or writing a resolver loop yourself.
Why this one
- Queries a real resolver, not a scrape. Every lookup goes to Cloudflare's public
DNS-over-HTTPS endpoint over HTTPS — the same service that answers
1.1.1.1— so there's nothing brittle to break when a target site changes its HTML. - All seven record types from one actor. A, AAAA, MX, TXT, NS, CNAME, SOA — pick per domain
by appending
:TYPEto the input, instead of running seven separate tools. - DNSSEC and recursion signal on every row.
dnssecValidatedandrecursionAvailablecome back with every lookup, useful for a security posture pass across a domain list without a separate DNSSEC checker. - Misses are free. NXDOMAIN, SERVFAIL, and a NOERROR response with zero answer records are all classified as not-found and never billed — you only pay for a domain that actually resolved.
- Row shape you choose.
expandRowsgives you one row per DNS record (handy for a spreadsheet or a Clay table) or one row per domain with all its records nested in an array — either way, you're billed once per domain, not per record.
What you get
Every row carries these fields. domain through dnssecValidated are the DNS-specific fields
(pulled straight from .actor/profile.json); the rest are the same envelope every actor in this
catalogue uses.
| Field | Type | Description |
|---|---|---|
query | string | The input exactly as given — example.com or example.com:MX |
found | boolean | true if the domain resolved for the queried type with at least one answer record |
status | string | "OK" on a found row; NOT_FOUND, BLOCKED, REQUEST_FAILED, or BAD_FORMAT on a miss |
domain | string | The queried domain, lowercased |
queriedType | string | The DNS record type that was queried: A, AAAA, MX, TXT, NS, CNAME, or SOA |
records | array | Every answer record Cloudflare returned for that type — name, type (numeric DNS type), ttl, and data per record |
recursionAvailable | boolean | The resolver's RA flag — whether recursive lookups were available for this query |
dnssecValidated | boolean | The resolver's AD (Authenticated Data) flag — true only when the response chain was cryptographically validated |
scrapedAt | string (ISO 8601) | Timestamp of the lookup |
message | string | Present only on miss rows — a human-readable reason (e.g. why the domain didn't resolve) |
With expandRows on (the default), each record in records becomes its own dataset row instead
of a nested array — same fields, one DNS record per row. If any data field name were to collide
with a reserved envelope key (query, found, status, message, scrapedAt), it would be
renamed to <key>Value in the output — that doesn't happen with this actor's current fields, but
it's the rule the shared harness applies across the whole catalogue so column names never
silently overwrite each other.
Price
$4 per 1,000 domains, plus a $0.005 start fee. Misses (found:false) are never charged.
That's $0.004 per resolved domain at the FREE tier, dropping to $0.0024 per resolved domain on
paid tiers — the $0.005 actor-start charge is fixed regardless of tier. 1,000 domains through
this actor: ~$4 if every one resolves, less for any that come back NXDOMAIN or SERVFAIL. The
same 1,000 rows through a credit-based enrichment platform: $80–$400. A domain that doesn't
resolve for the queried type costs you nothing either way — you still get a row (found: false),
you just aren't billed for it.
How to use
- In the Apify Console. Open the actor page and click Start — the
domainsfield is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found. - Via the API. Call it directly with a POST request — no Console needed once you have an API token:
curl "https://api.apify.com/v2/acts/accountable_eel~dns-record-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"domains":["github.com"]}'
- On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.
- Paste a list of domains into the input, one per line.
github.comon its own queries theArecord by default. - To query a different record type, append
:TYPE—github.com:MX,cloudflare.com:TXT,example.com:SOA. Want two types for the same domain? List it twice, once per type — each is billed independently. - Turn on Try it first (
testRun) to run just the first 5 items and check the shape of the output before committing to a full list. - Turn on Hide rows with no result (
onlyFound) if you only want rows that actually resolved in your dataset — misses are free either way, this just keeps them out of the export. - Leave
maxConcurrencyat its default of 5 unless you have a reason to push it — this target has no browser fallback, so a burst of parallel requests risks getting rate-limited rather than finishing faster. - Run it, then export the dataset as CSV/JSON or pull it via the API into whatever pulls your enrichment data — Clay, n8n, a script, or an agent.
Input
{"domains": ["github.com"]}
One domain per line. Defaults to an A record lookup; append :TYPE (A, AAAA, MX, TXT, NS, CNAME, or SOA) to query a different record type, e.g. github.com:MX. Accepted formats: github.com, github.com:MX.
{"items": ["github.com", "github.com:MX", "cloudflare.com:TXT"],"maxConcurrency": 5}
items is a list of domains to query. By default each domain is queried for its A
record; append :TYPE (one of A, AAAA, MX, TXT, NS, CNAME, SOA) to query a
different record type, e.g. github.com:MX. One dataset row is returned per item; rows
with "found": false are never charged. maxConcurrency controls how many DNS queries
run in parallel — this target has no browser fallback, so keeping it conservative avoids
getting rate-limited.
Sample output
| query | found | status | domain | queriedType | records | recursionAvailable | dnssecValidated | scrapedAt |
|---|---|---|---|---|---|---|---|---|
| github.com | true | OK | github.com | A | true | false | 2026-08-24T06:01:23.530Z |
One row per item, for example:
{"query": "github.com:MX","found": true,"data": {"domain": "github.com","queriedType": "MX","records": [{ "name": "github.com", "type": 15, "ttl": 3600, "data": "1 aspmx.l.google.com." }],"recursionAvailable": true,"dnssecValidated": false},"scrapedAt": "2026-08-21T10:00:00.000Z"}
Domains that don't resolve for the queried type — NXDOMAIN, SERVFAIL, or a NOERROR
response with no answer records — still get a row ("found": false), so you always get
one row per input, but you're never charged for those.
Use it from Clay, n8n, Make, or an AI agent
This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.
curl "https://api.apify.com/v2/acts/accountable_eel~dns-record-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"domains":["github.com"]}'
n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~dns-record-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"domains":["github.com"]} (swap in an expression from an earlier node for a real value).
Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~dns-record-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"domains":["{{domain}}"]}, mapping the row's domain into the domains array.
MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "DNS Record Lookup | Apify" — the agent will find and run this actor.
Tips
- Query more than one record type for the same domain by listing it twice —
example.com:Aandexample.com:MXas separate input items. Each is billed independently as its own lookup, so you only pay for the types you actually ask for. dnssecValidated: falsedoesn't mean "no DNSSEC." It reflects Cloudflare'sADflag for that one query —trueonly when the resolver could cryptographically validate the response chain. Afalsecan mean DNSSEC isn't configured, or just that validation wasn't attempted for that lookup. If you need a definitive DNSSEC posture, cross-check afalseagainst the domain'sDNSKEY/DSrecords directly.- Turn
expandRowsoff if you want one row per domain. With multipleMXorTXTrecords, the default (on) gives you one row per record — cleaner for filtering, but it multiplies row count on domains with a lot of records (still billed once per domain either way). - Keep
maxConcurrencyat 5 for large batches. This target has no browser fallback to fall back on if Cloudflare starts throttling you, so slow-and-steady finishes a 10,000-domain list more reliably than a burst that gets rate-limited partway through. - Use
MXandTXTtogether for a quick deliverability read before a cold outreach or domain migration —MXtells you where mail routes,TXTsurfaces SPF/DMARC records (look forv=spf1orv=DMARC1in thedatafield). - Resolve
A/AAAA/CNAMEacross a domain list for infrastructure discovery — the IP or CNAME target tells you which host, CDN, or cloud provider a domain points to, without visiting the site. - Check
NSandSOAafter a DNS cutover to confirm propagation finished — query the same domain before and after a migration and diff therecordsarray. - Run
dnssecValidatedacross a portfolio you manage as a lightweight security-posture pass — it won't replace a dedicated DNSSEC audit, but it flags which domains are worth a closer look.
vs. alternatives
| What it costs | What you get | Trade-off | |
|---|---|---|---|
This actor (dns-record-lookup) | $0.004 per resolved domain (FREE tier, down to $0.0024 on paid tiers), $0.005 actor start, nothing for NXDOMAIN/SERVFAIL | One row per domain or per record — A/AAAA/MX/TXT/NS/CNAME/SOA, plus DNSSEC and recursion flags, from one API call | One resolver (Cloudflare's), one record type per query item — no zone transfer, no historical record archive |
DIY (whois/dig) | Free, your time | The same records, one domain at a time from a terminal | Fine for a handful of domains; across a list of thousands you're writing your own retry logic, rate limiting, and parsing to get a flat table out of it |
| Clay | $0.08–$0.40 per enriched row in credits, on top of a seat | A whole enrichment workspace — waterfalls across dozens of providers, plus the table and the sequencing around it | If you want one place that does everything and you're not counting rows, that's Clay. This is one column, priced per column, callable from Clay via its HTTP step. |
Prices for third-party tools are their published list prices as of August 2026 and are not tracked here — check the vendor before relying on the comparison.
FAQ
What happens if a domain doesn't resolve — do I still pay?
No. NXDOMAIN, SERVFAIL, and a NOERROR response with zero answer records for the queried type are
all treated as a miss (found: false, with a status of NOT_FOUND, BLOCKED, REQUEST_FAILED,
or BAD_FORMAT). Misses still produce a dataset row so your row count matches your input count,
but they're never billed.
Do I need a Cloudflare API key? No. Cloudflare's DNS-over-HTTPS resolver is free and public — this actor calls it directly, with no credentials required on your end.
Are there rate limits I should worry about on a large batch?
maxConcurrency (default 5) controls how many DNS queries run in parallel. This target has no
browser fallback, so keep it conservative on large runs — a burst of parallel requests risks
getting throttled rather than finishing faster. A list of a few thousand domains at the default
concurrency runs without issue.
How fresh is the data — could I get a stale record?
Every run queries Cloudflare's resolver live, so you get whatever it's currently serving. That
said, DNS itself is cached: Cloudflare's resolver respects each record's TTL, so a record that
changed in the last few minutes (or hours, for a long-TTL SOA or NS record) may not have
propagated to the resolver yet. This actor reports what the resolver has right now, not a
guaranteed real-time read of the authoritative nameserver.
Do I need to configure a proxy? No. Requests go to Cloudflare's public resolver, not to the target company's own infrastructure, so there's nothing to spoof or rotate around. The proxy configuration field is there because the shared actor template includes it, but DNS-over-HTTPS to Cloudflare doesn't need one.
Is DNS record data personal data under GDPR? DNS records describe a domain's infrastructure — IP addresses, mail servers, nameservers, TXT policy strings — not people. They're not personal data, and this actor doesn't process, store, or return anything about individuals.
Can I schedule this to run on a cadence?
Yes, through Apify's own Scheduler — set up a recurring run against a saved input (e.g. a
maintained list of domains you monitor) and it queries fresh on each run. There's no built-in
delta/diff feature here — every run is a full lookup against the current input list, so if you
want to know what changed between runs, keep the previous dataset export and diff it yourself
against the new one, or expand TXT/MX/NS and compare the record values.
Can an AI agent call this directly?
Yes. It's registered on the Apify MCP server — a client like Claude or Cursor can find and run it
by name ("DNS Record Lookup | Apify") — or call the Apify API directly over HTTP, same as the
curl example above.
Related actors
- Domain RDAP Lookup — registration data (registrar, creation/expiry dates, nameservers) for the same domain list, from RDAP instead of DNS.
- Email Deliverability Check —
mail route, disposable/role detection, and provider fingerprint for a domain, building on the
same
MX/TXTsignal this actor surfaces raw. - Tech Stack Lookup — what a domain is actually running (CMS, analytics, ecommerce platform), for when DNS tells you where it points but not what's there.