Domain Health Report: DNS, Email Auth, TLS, Expiry
Pricing
$2.50 / 1,000 domain reports
Domain Health Report: DNS, Email Auth, TLS, Expiry
Score 0-100 per domain: registration & expiry (RDAP/WHOIS), DNS, SPF/DKIM/DMARC/MTA-STS, TLS certificate, HTTPS redirect. Bulk, no login.
Pricing
$2.50 / 1,000 domain reports
Rating
0.0
(0)
Developer
Francesco Antonio Russo
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Domain Health Report
One record per domain with a 0-100 score, a letter grade and a list of coded issues, built from four public sources:
| Area | What is checked | Source |
|---|---|---|
| Registration | registrar, creation & expiry dates, days to expiry, EPP status locks (transfer lock, hold, pending delete), DNSSEC flag | registry RDAP (RFC 9083): IANA bootstrap + DENIC (.de), SWITCH (.ch/.li), .io, .us; .it via the Registro .it WHOIS; registries with no readable service (.eu, .es …) return null with a note |
| DNS | apex A/AAAA, www, nameservers (redundancy), MX & null-MX, CAA (climbing parents, RFC 8659) | public DNS |
| Email security | SPF (syntax, all qualifier, top-level lookup count, duplicates), DMARC (policy, pct, rua, org-domain fallback for subdomains), DKIM on ~40 common selectors + yours, MTA-STS record and policy file, TLS-RPT, BIMI, mail provider guess | DNS + HTTPS |
| HTTPS / TLS | handshake on 443, chain trust, issuer, expiry, name coverage (SAN/wildcard), protocol version, HTTP→HTTPS redirect, HSTS | TLS + HTTP HEAD |
No login, no API key, no browser: it reads only data the domain owner publishes to the world. Registrant contact data is never extracted.
Typical uses: monitor your own portfolio for expiring domains and certificates · qualify a lead list (who has broken SPF/DMARC, who still runs on p=none) · due diligence before buying a domain · MSP/agency health checks across clients · enrich a CRM with mailProvider, registrar, server.
Input
{"domains": ["github.com", "https://www.cloudflare.com/", "info@repubblica.it", "expired.badssl.com"],"checkRegistration": true,"checkEmail": true,"checkTls": true,"dkimSelectors": ["mycompany2026"],"includeRawRecords": false,"timeoutSecs": 15,"concurrency": 10,"maxDomains": 0}
domains accepts domains, URLs and email addresses, mixed. www. is stripped; subdomains are kept and also reported against their registrable domain (registrableDomain). Shared registry zones such as co.uk, ac.uk, com.au, com.br, com.pl or co.jp are not domains and are skipped as invalid (the message says so). Government zones (gov.uk, gov.br, gov.sg, gov.tw, gov.au, go.kr, gob.es ...) and nhs.uk are real names, often with a site and mail of their own, and are checked like any domain; a government zone without a site (a gov.xx that does not answer) still produces a normal report, which is charged like any other domain; only a name that is neither in DNS nor registered comes back as free nonexistent. Duplicates are checked once; invalid entries are logged and skipped, never charged (if the list has no valid domain at all, each bad entry is written as a free record with status: "invalid" and the run still finishes normally). Names that do not exist (NXDOMAIN and no registration found) come back as status: "nonexistent" and are free. Switching off all of checkRegistration, checkEmail and checkTls is rejected as an input error (the report would be DNS-only). A report whose checks could not all run (coverageComplete: false, see checkErrors) is delivered but not charged and never graded above C.
Output (dataset)
One record per domain, 60 typed fields — every field is documented in the dataset schema (visible under Storage → Dataset → Schema). A real record (2026-10-06):
{"domain": "repubblica.it","registrableDomain": "repubblica.it","score": 84,"grade": "B","criticalCount": 0,"issueCodes": ["NO_TRANSFER_LOCK","NO_DNSSEC","NO_CAA","DMARC_POLICY_NONE","MTA_STS_MISSING","TLS_RPT_MISSING","HSTS_MISSING"],"registered": true,"registrar": "Gandi SAS","expiresAt": "2027-01-16T00:00:00.000Z","daysToExpiry": 101,"dnssec": false,"nameservers": ["ns-1477.awsdns-56.org","ns-1541.awsdns-00.co.uk","ns-353.awsdns-44.com","ns-723.awsdns-26.net"],"mailProvider": "Microsoft 365","spfRecord": "v=spf1 ip4:178.23.254.18 include:spf-smtp.kataweb.it include:spf.protection.outlook.com include:musvc.com -all","spfAll": "-","dmarcPolicy": "none","dkimSelectorsFound": ["selector1"],"tlsTrusted": true,"certIssuer": "Amazon","certDaysToExpiry": 153,"redirectsToHttps": true,"hsts": false,"coverageComplete": true,"checkErrors": [],"durationMs": 3699,"issues": [{"code": "DMARC_POLICY_NONE","severity": "medium","area": "email","message": "DMARC p=none: monitoring only, spoofed mail is still delivered."}]}
Score and grade
score = 100 − Σ penalties with critical 25 · high 12 · medium 6 · low 2 · info 0, floored at 0.
Grade: A ≥ 90 · B ≥ 75 · C ≥ 60 · D ≥ 40 · F below 40 or any critical issue.
Issue codes
| Code | Severity | Meaning |
|---|---|---|
DOMAIN_NOT_REGISTERED · DOMAIN_EXPIRED · DOMAIN_ON_HOLD · DOMAIN_PENDING_DELETE | critical | registry says the domain is gone, expired, on hold or being deleted |
DOMAIN_EXPIRY_DATE_PASSED | low | the registry's expiry date has passed but it still shows the domain active (.it ok / autoRenewPeriod, RDAP auto renew period): normally an automatic renewal whose date is not updated yet, so it is not reported as expired |
DOMAIN_EXPIRES_30D / DOMAIN_EXPIRES_90D | high / medium | registration expiry within 30 / 90 days (some registrars show the registry date, which auto-renews) |
NO_TRANSFER_LOCK · NO_DNSSEC | low | no transfer lock where the registry publishes lock states (never for DENIC, SWITCH, Nominet, registro.br, .it: transferLock is null there); delegation not DNSSEC-signed |
RDAP_UNAVAILABLE | info | registration could not be read: the registry has no RDAP/WHOIS we can read (e.g. .ru, .eu, .so) - then the record stays complete; a registry that times out, throttles (429), fails (5xx) or gives any answer other than data / not-registered (e.g. 401, 403, 426) even after retries gives an incomplete free record instead (a registry that answers 426 Upgrade Required over HTTP/1.1, like .tw, is asked again over HTTP/2); also when the registry has no record for a delegated name or for the registrable domain of a subdomain such as mail.lse.ac.uk, which is never reported as unregistered) |
CHECK_FAILED | high (dns) / medium | a whole check area could not run; the record is not charged and its grade is capped at C |
DOMAIN_NOT_DELEGATED | critical | NXDOMAIN: the name does not exist in the DNS (unregistered, or registered without nameservers) |
APEX_NO_ADDRESS · WWW_NO_ADDRESS · SINGLE_NAMESERVER · NO_NS_RECORDS · NO_CAA | high · medium · medium · low · low | DNS gaps |
SPF_MISSING · SPF_MULTIPLE · SPF_TOO_MANY_LOOKUPS | high | no SPF; two SPF records; more than 10 DNS-lookup terms counting through include: and redirect= (permerror, RFC 7208 §4.6.4; spfLookups holds the count) |
SPF_PLUS_ALL | critical | +all: anyone can send as the domain |
SPF_NEUTRAL_ALL · SPF_NO_ALL · SPF_SYNTAX | medium · medium · low | weak or malformed SPF |
DMARC_MISSING · DMARC_INVALID | high (medium without MX) | no / broken DMARC |
DMARC_POLICY_NONE · DMARC_PARTIAL_PCT · DMARC_NO_RUA | medium · low · low | monitoring-only, partial, or unreported DMARC |
DKIM_NOT_FOUND · MTA_STS_MISSING · MTA_STS_POLICY_UNREACHABLE · TLS_RPT_MISSING | low · low · medium · info | mail transport hardening. MTA_STS_POLICY_UNREACHABLE = the policy file answers 404/4xx/redirect, has a bad certificate, refuses the connection or its host does not exist; a timeout, reset, 429 or 5xx that repeats on a second attempt gives an incomplete free record instead |
NO_MX_NO_POLICY | low | domain sends no mail but publishes no v=spf1 -all / reject DMARC: still spoofable |
HTTPS_UNREACHABLE · HTTPS_SERVER_ERROR | high | port 443 does not answer, confirmed by a second attempt made later at low concurrency (a failure that does not repeat, or one that contradicts an https:// answer, gives an incomplete free record instead) / answers 5xx |
HTTPS_LEGACY_ONLY · TLS_NEGOTIATION_FAILED | high | the server only completes a handshake with obsolete TLS 1.0/1.1 / it answers on 443 but refuses every modern handshake (probably obsolete ciphers or weak key sizes) - or, when the TLS alert is 112 "unrecognized name", it rejects the host name itself (no certificate or virtual host for it), which the message says |
TLS_LEGACY_PROTOCOL | medium | the server still accepts TLS 1.0 and/or 1.1 next to modern versions (tlsLegacyProtocols) |
TLS_UNTRUSTED · TLS_NAME_MISMATCH · TLS_EXPIRED | critical | certificate chain, name or validity broken (each defect is reported once: an expired certificate as TLS_EXPIRED, a valid chain issued for another name as TLS_NAME_MISMATCH) |
TLS_INCOMPLETE_CHAIN · TLS_EXPIRES_14D | high | server omits its intermediate certificate (strict clients fail, browsers often cope); certificate about to expire |
HTTP_NO_REDIRECT · HSTS_MISSING | medium · low | the redirect chain from http:// (up to 4 hops) never reaches https://; no HSTS on a 2xx/3xx HTTPS answer |
Codes are stable: filter on issueCodes in your integration.
Pricing
Pay per event: one event per complete domain report delivered (domain-report). Invalid entries, nonexistent names, including a subdomain that does not exist under a registered domain (status: "nonexistent"), incomplete reports (coverageComplete: false) and domains skipped because of your budget cost nothing. Set Max domains or a run budget to cap large lists. Example: a list of 200 names where 3 do not exist and 2 reports are incomplete is 195 events; the price per event is on the Actor's Pricing tab.
Limits and honesty
- Registration data depends on the registry:
.itis read from WHOIS (one query at a time, the Registro throttles per IP); DENIC (.de), SWITCH (.ch,.li) and Nominet (.uk) publish status but no expiry date;.eu,.esand a few others publish nothing readable →registered: null,registrationNotesays why. - A few registries never deliver registration data, whatever the retries:
.na(the registry does not answer),.sn(its RDAP gives free French text instead of a standard domain object), and.cr(its RDAP server presents a self-signed certificate, so it is not trusted). Those domains come back as incomplete and free (for.nathe note says the registry does not answer) (coverageComplete: false,checkErrorssays why, never charged); they cannot reach a complete report until the registry changes. Zones a registry runs itself, such asgo.kr(the registry answers that it is not a registrable name), have no registration data either, but that is a definite answer:registered: null, the note says why, the rest of the report is complete. - SPF lookups follow
include:andredirect=(depth 10, at most 30 terms; a failed nested lookup makes the count a lower bound). Void lookups and the 10-name MX limit are not evaluated. - DKIM can only be found, not proven absent: a domain using a selector outside the probed list gets
DKIM_NOT_FOUND(low). Add your selectors indkimSelectors. - "Expires in N days" is the registry's date; many registrars auto-renew shortly before.
- TLS is checked on the apex host only (not
www), with Node's root store. Obsolete TLS 1.0/1.1 are probed with two extra handshakes (tlsLegacyProtocols); RC4, 3DES, NULL and export ciphers are not probed (the runtime has them compiled out), so a server that offers only those is reported asTLS_NEGOTIATION_FAILED, not as "weak ciphers". Certificate revocation is not checked. - The score covers the checks you enabled (
checksRun): with HTTPS checks off, a broken certificate cannot lower it. - DNS lookups go to the system resolver, at most 16 at a time. A query that gets no answer (timeout, refused, SERVFAIL) is asked again once on the same resolver and then on the public resolvers 1.1.1.1 and 8.8.8.8 (only the domain names being checked are sent to them). "No such name" and "no such record" are answers and are never retried. If every resolver fails, the record is delivered as incomplete (
coverageComplete: false) and is free. TLS and HTTP connections (including the MTA-STS policy download, the RDAP requests and the.itWHOIS connection) reuse the addresses the DNS check found and resolve other names (redirect targets) through the same resolver, handing over to the operating system if it takes longer than 4 s. The run raises Node's thread pool (UV_THREADPOOL_SIZE) to 64 unless you set it yourself. HTTPS_UNREACHABLEis reported only after three attempts when all of them time out (the second after 1 s, the third after 4 s, both through a narrow gate); a refusal or a reset is an answer and is not repeated.dmarcRuaandmxrepeat operational addresses the domain itself publishes in public DNS.- This is a technical screening, not a security audit or a legal compliance statement.
API & integrations
Run it from your code and read the dataset in one call (token = your Apify API token):
curl -X POST "https://api.apify.com/v2/acts/far003~domain-health-report/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"domains":["github.com","cloudflare.com"]}'
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('far003/domain-health-report').call({ domains: ['github.com', 'cloudflare.com'] });const { items } = await client.dataset(run.defaultDatasetId).listItems();
from apify_client import ApifyClientclient = ApifyClient(os.environ["APIFY_TOKEN"])run = client.actor("far003/domain-health-report").call(run_input={"domains": ["github.com", "cloudflare.com"]})items = client.dataset(run["defaultDatasetId"]).list_items().items
Schedule it weekly on your portfolio and add a webhook on ACTOR.RUN.SUCCEEDED to get the records into Slack, Google Drive, Zapier or Make. The dataset exports as JSON, CSV, Excel and XML.
Changelog
- 2026-10-15 — subdomains of delegated names (
mail.lse.ac.uk) are no longer reported as unregistered; registries that answer 400 to a subdomain (.org,.io,.info,.dev,.app,.ai,.pl,.au) are climbed to the registrable domain;HTTPS_UNREACHABLEneeds a confirming second attempt and TLS/HTTP sockets are capped at 20 at once, so high concurrency no longer produces false findings. - 0.1 (2026-10) — first release: registration (RDAP incl. DENIC/SWITCH/.io/.us +
.itWHOIS), DNS, SPF/DMARC/DKIM/MTA-STS/TLS-RPT/BIMI, TLS/HTTPS with redirect chain, coverage flag, score and 45 issue codes.