Domain Health Report Fields
The field reference for the report datapulse_live_domain_health returns in raw_output. For what the tool does, how to call it and how to read the verdict, see datapulse_help(topic="domain_health").
Conventions
Arrays are always present, never
null; an empty list is[]. Booleans are always present.The report distinguishes “we looked and the answer is no” from “we could not tell”, everywhere. Several checks can come back not-determined, and each says so in its own way:
Field Not determined as nameservers.serials_consistentnullnameservers.ipv4_prefixes_24,ipv6_prefixes_48nullwildcard.consistentnullcaa.hosts.*.permittedabsent, with notesaying whymail.dmarc.unresolvedtruewildcard.status"unknown"tlsa.result"unknown"hsts_preload"unknown", withhsts_preload_errordns.resolver_reachable.*a skipped:stringNot determined is neither the good case nor the bad one. Branch three ways.
Both shortcuts are wrong, in opposite directions. Folding
nullinto the pass reports a clean audit for a run that checked nothing. Folding it into the fail is worse:if serials_consistent is not true then the servers disagreeturns “no nameserver answered” into “the nameservers disagree with each other”, which is an affirmative finding someone will act on. The same inversion hides inif prefixes == 0 then there is no diversityand inif wildcard.status != "present" then there is no wildcard, which foldsunknownintoabsent.if serials_consistent is null: not determined — say so, or omit the finding elif serials_consistent: the serials agree else: the serials disagreewildcard.statusis the same three-way choice carried as a value rather than a null:present,absent,unknown.An object is omitted only when the whole check did not apply:
mailandnameserversfor a name that is not a zone apex,mailalso for a name that cannot receive mail at all (one carryingreserved_nameorpublic_suffix, or one that does not exist),web.wwwfor anything that is not a registrable domain,gluewhen the parent could not be asked,tlswhen 443 did not answer,quicwhen the probe was not run,hstswhen no header was served,web.apex/web.www(andwebitself, as{}) when the name resolved to no usable addresses.Optional scalars appear only when they have a value:
unicode_domain,not_a_zone,enclosing_zone,reserved_addresses,hsts_preload_covered_by,hsts_preload_policy,hsts_preload_error,cname,retries,ede,detail,parent_only,child_only,error.Warning and error strings are stable; key on them by prefix (
apex: certificate expired,www (ipv4): redirect chain,nameserver <name>:,resolver returned SERVFAIL:,apex: CAA records do not permit,MTA-STS:,DKIM selector,HSTS).Findings are per host and cause, not per address, and carry a count:
apex: certificate expired on 1 of 1 addresses: ...,apex: certificate handshake failed on 7 of 7 addresses: .... No address appears in a finding. Which address failed is in thewebsection, underweb.apex.ipv4[].tlsand its IPv6 equivalent. The nameserver findings already had this shape.Error text from a probe carries only the condition, not the socket that hit it:
i/o timeout, notread tcp4 10.12.60.35:46962->80.245.156.34:443: i/o timeout. That applies totls.error, the HTTP resulterrorand the MTA-STS fetch error as well as the finding text, so two runs that failed the same way now compare equal instead of differing by an ephemeral port.
Top level
| Key | Type | Meaning |
|---|---|---|
domain | string | A-label of the probed name |
unicode_domain | string | U-label, IDN only |
not_a_zone, enclosing_zone | bool, string | Present when the name is a host inside a zone; enclosing_zone when a SOA revealed it |
resolver | string | Resolver used for validated lookups (127.0.0.1:8053 in production) |
families | list | Address families used for the web probes: ipv4, ipv6 |
timeout_sec, tcp_timeout_sec, quic_timeout_sec | int | Probe budgets |
dns_concurrency | int | How many DNS helper processes the run was allowed in flight at once (0 means unlimited). Set by the worker, not by the caller; it bounds load, not results, so two runs of the same domain under different caps produce the same report |
dns | object | apex and www maps keyed by record type, plus resolver_reachable |
dnssec | object | state, ds, dnskey, optional ede, detail |
delegation | object | status, parent_ns, parent_server, child_ns, child_server, optional parent_only, child_only, error |
web | object | apex and www host objects, or {}. www is probed only for a registrable domain, one label below a public suffix: www.jeff.co.uk is a name someone would configure, www.old.reddit.com is one only this tool would ever ask for |
mail | object | Mail posture. Absent for a non-apex, reserved, nonexistent name or a public suffix |
nameservers | object | Nameserver audit (zone apexes only) |
caa | object | CAA verdict per host |
tlsa | object | DANE verdict |
wildcard | object | Wildcard detection |
reserved_addresses | list | Addresses in reserved ranges, when any |
public_suffix | bool | The name is itself a public suffix, such as com or co.uk. Mail is skipped for it, because a missing DMARC record on a registry’s own TLD is advice nobody can act on, and web.www is absent. Private suffixes such as github.io are ordinary domains their owners operate and keep their mail checks |
reserved_name | string | The RFC reserving this name, for suffixes outside the global DNS: invalid, test, localhost, example (RFC 6761), local (RFC 6762), onion (RFC 7686), home.arpa (RFC 8375). Such a name never resolves by definition, so dnssec.state reads unknown rather than bogus, delegation and zone checks are skipped, and one warning explains why. example.com and its siblings are reserved for documentation but are really delegated, so they are checked like any other domain |
hsts_preload | string | preloaded (browsers enforce HSTS for this name), absent (list consulted, name not covered), unknown (list could not be obtained) |
hsts_preload_covered_by | string | The ancestor entry whose includeSubDomains makes this name preloaded, when it is not the name itself |
hsts_preload_policy | string | Chromium’s policy for the covering entry, when preloaded. bulk-legacy, bulk-18-weeks, bulk-1-year: submitted through hstspreload.org, must keep serving a compliant header, and warn when they do not. google, custom, public-suffix, public-suffix-requested, test: kept by hand, no header owed, never warn |
hsts_preload_error | string | Why the list could not be obtained, when hsts_preload is unknown |
errors, warnings | list | Findings; see “Reading the verdict” |
ok | bool | true when errors is empty |
elapsed_ms | int | Probe wall time |
dns
Each entry under dns.apex (keys A, AAAA, MX, NS, TXT) and dns.www (A, AAAA) has status (ok, nxrrset, nxdomain, failure, timeout), trust (secure, insecure, bogus), records (rdata strings, when any), and optionally cname (chain followed), error, retries (a query retried after a timeout, the same key the nameserver audit uses). dns.resolver_reachable maps ipv4 / ipv6 to yes, no, or a string starting with skipped that names the reason. It measures the configured resolver, not the domain being probed: the check is exempt from dns_concurrency, so a target whose own nameservers hang cannot starve it and make a healthy resolver read no.
web
web.apex and web.www each have:
| Key | Type | Meaning |
|---|---|---|
ipv4, ipv6 | list | One address entry per address |
same_as_apex | bool | www resolves to exactly the apex’s addresses (www only) |
(no www key) | — | web.www is present only for a registrable domain. For a host inside a zone, a CNAMEd name or a public suffix there is no www anyone would configure, and asking for one invited a catch-all answer served with a certificate that could not cover the extra label, reported as a hostname mismatch on a healthy site |
via_wildcard | bool | www is answered by the zone’s wildcard (www only) |
redirects | object | Per family (ipv4, ipv6): hops (url, status), ended, final_url, external (target outside apex/www, not followed), loop, error. Read ended, not the absence of final_url. It says why the chain stopped: final (a terminal response, with final_url set), external (the next hop left the zone and was deliberately not followed), loop, hop_limit or error. A chain that hands off externally is finished rather than truncated, and its last status is the redirect that left rather than a terminal 200, so without ended a healthy domain such as github.io looks broken |
cert_consistent | bool | All addresses of this host served the same certificate |
Each address entry:
| Key | Type | Meaning |
|---|---|---|
ip | string | The address |
80, 443 | string | open, refused, timeout, unreachable, error, skipped (reserved address) |
http, https | object | One GET /: status, location, server, hsts (max_age, include_subdomains, preload), error |
tls | object | chain (the headline defect), chain_problems (every defect, headline first), version, alpn, cipher, tls10, tls11 (legacy protocol accepted), cert, chain_length, error |
tls.cert | object | subject, issuer, not_before, not_after, days_remaining (negative when expired), sans, covers_apex, covers_www, wildcard, key, fingerprint_sha256. issuer is whatever the served chain says, and CAs rotate intermediates: Let’s Encrypt now issues from YR1, YR2 and YE2 rather than the older R and E series, so an unfamiliar name there is not itself a finding. chain is what says whether the chain verified |
tlsa | string | match, mismatch, none — only when TLSA records exist |
quic | object | supported, alpn, tls_version, server_addr, handshake_ms, error; on a failure (reports since 2026-09-15) also reason — timeout, tls_rejected, resolve_failed, version_negotiation, stateless_reset, transport_error, application_error, listen_failed, invalid_args or other — and, for tls_rejected, tls_alert (e.g. “handshake failure”) and tls_alert_code (e.g. 40). A CDN with HTTP/3 disabled reads tls_rejected with alert 40; a host that drops UDP reads timeout |
What the TLS verdict covers, and what it does not. chain names the single most urgent defect; chain_problems lists every one of them, headline first. The badssl fallback certificate is both expired and served for a name it does not cover, and reads chain: "expired" with chain_problems: ["expired", "hostname_mismatch"]. Key on chain for a headline and iterate chain_problems before telling anyone the certificate is fixed, because renewing on the strength of chain alone would leave the site broken.
incomplete_chain and untrusted_root are close together and easy to confuse. incomplete_chain means the server did not send the intermediate, but the certificate’s AIA URL was fetched and that repair produced a chain that verifies. The URL is named in tls.error on the affected address, and only there: there is no AIA field on tls.cert. untrusted_root means the chain does not verify even with the intermediate supplied, whether or not an AIA fetch succeeded. The distinction cannot be read off the issuer’s name, because a certificate can be issued by a CA whose name is well known under a root no trust store carries.
valid and incomplete_chain differ in who has to do the repair, and that decides which clients break. A browser generally fetches the missing intermediate itself, so an incomplete chain often looks fine in Chrome while failing in curl, Java and some mobile clients. One address of a host can be misconfigured while its sibling is correct, so the same name can report valid and incomplete_chain at once, which is why every address is probed rather than one.
Live examples of incomplete_chain are transient by nature: a domain observed serving one certificate on one address may be repaired within hours, and un.org was fixed on 2026-09-07 between two probes. Treat a public domain as a snapshot, not a fixture.
valid means the chain as served verified against the trust store at probe time, with no repair needed. It is not a statement about revocation, which is not checked, so a revoked certificate whose chain is intact reports valid. cert.key and the signature algorithm are reported but not judged: there is no weak-key or weak-signature finding, so a 1024-bit RSA key appears in the output without a warning attached.
mail
Present only for a name that could configure mail: absent for a host inside a zone, for a reserved name, and for a name that does not exist. Its absence is the answer, not a gap.
| Key | Meaning |
|---|---|
dmarc | present, unresolved, policy, subdomain_policy, pct, rua (reporting address present), records (count), problems. unresolved is true when the _dmarc lookup did not complete, which is not the same as a domain publishing no DMARC record |
spf | records (count), lookups (DNS-querying terms, limit 10), void_lookups, txt_answer_octets (the apex TXT reply size without EDNS, reports since 2026-09-15; warned past 450 and 512 octets, the RFC 7208 §3.4 UDP limit), all (the all qualifier, e.g. -all), includes, problems |
mx | One entry per MX: host, preference, addresses (count), cname, ip_literal, unresolved, problems. A null MX appears as host . with addresses 0. unresolved means the target’s address lookup did not complete, which is a gap in the check rather than a fault in the domain and does not fail it |
dkim | selectors_found, revoked (selectors publishing an empty key), wildcard. A random selector is probed as a negative control: when it answers, the zone wildcards _domainkey, wildcard is set and no selector is named, because every guess would answer. Selectors cannot be enumerated, so an empty list is a fact, not a finding |
mta_sts | record, id, mode, max_age, mx (policy patterns), policy_ok, mx_covered, error |
tls_rpt | TLS-RPT record present |
nameservers (zone apexes only)
| Key | Meaning |
|---|---|
count | Distinct NS names |
servers | One entry per NS address: name, ip, aa (answered authoritatively), rcode, serial, no_soa (answered authoritatively with no SOA in an untruncated response, so an absent serial is a recorded fact rather than a missing key; a truncated UDP answer is not counted, since it looks identical in the first message of the audit’s three-query run), tcp, edns, retries (present as 1 when the first audit query went unanswered and a retry succeeded), error |
A nameserver’s verdict turns on whether it answered at all, not on how many addresses failed:
| Observed | Verdict | Finding |
|---|---|---|
| Answered but disclaimed authority | Error at any count | nameserver <name>: not authoritative ... |
| Silent on every address | Error | nameserver <name>: no answer on N of N addresses |
| Silent on some addresses | Warning | nameserver <name>: no answer on N of M addresses, the others are authoritative |
Answering with REFUSED on one address of nine is proven lameness and stays an error; a node that merely goes quiet while its siblings answer authoritatively is a warning, because a flaky anycast node is not a misconfiguration of the domain. The reason for a silent address is the fixed text no answer, rather than whichever of dig timed out or no servers could be reached arrived first, so the string no longer varies between runs on the same domain.
| serials_consistent | Every server reported the same SOA serial, or null when no server answered authoritatively and nothing was compared. true means the serials were actually checked. The drift warning names the address as well as the name, because the disagreeing server is often one node behind an anycast address: aluminium-supplier.com has a node of dns9.hichina.com serving serial 2016081111 while its siblings serve 2026082616, a decade apart |
| ipv4_prefixes_24, ipv6_prefixes_48 | Distinct prefixes across all addresses; 1 means no diversity, null means no address was examined |
| glue | required (in-bailiwick names), missing, mismatch; omitted when the parent could not be asked, or when no nameserver address was known to compare it against |
| ns_cname, unresolvable | NS names that are CNAMEs, or that the resolver said have no address. Both are errors |
| unresolved | NS names whose address lookup never completed. A gap in the check rather than a fault in the domain, so it is a warning, not an error |
caa
caa contains hosts and nothing else: one verdict for apex and one for www, each judged against the certificate that host actually served. There is no domain-wide CAA verdict, because a domain need not have one.
| Key | Meaning |
|---|---|
published | The CAA records at that name. [] for a name that publishes none of its own |
effective | The records that govern the name, after the RFC 8659 climb. A www that publishes nothing shows the apex set here |
issuer | Organisation of the certificate that host served |
permitted | Whether effective allows that issuer |
note | Why no verdict was reached, when permitted is absent |
Both arrays are always present. published empty alongside a non-empty effective is how the report says the set was inherited from the apex.
permitted is true when no records govern the name (any CA may issue). It is absent whenever nothing could be judged, and note distinguishes two materially different reasons, which a caller must not collapse:
- Nothing to check.
no certificate observed, because the host serves no TLS, so there is no issuer to compare against the policy. This is by far the common case: in one 49-domain batch all 42 null verdicts were this one. The policy was read fine; there was simply nothing to judge against it. - Could not check. The CAA lookup did not complete, so the policy itself is unknown.
issuer not in the CAA mapping tableis a third, narrower variant of the same idea.
The difference matters because “any CA may issue” is a security-relevant all-clear, and it is never derived from a query that failed. A host with no TLS is unremarkable; a policy that could not be read is a gap in the check.
A wildcard certificate is judged against issuewild when the governing set has one, so a CA that issue permits can still be forbidden for wildcards (RFC 8659 gives issuewild precedence for wildcards).
A CAA identifier need not resemble the issuer’s organisation name. A CA that has acquired other CAs honours each brand’s identifier at issuance, so posteo.de permits geotrust.com and is correctly served a certificate whose organisation reads DigiCert Inc, DigiCert having acquired GeoTrust. Reading caa.hosts.*.issuer beside published will therefore turn up pairs that look mismatched and are not, and the verdict in permitted accounts for the brands each CA issues under. Do not re-derive it by comparing the two strings yourself.
Two hosts can reach opposite verdicts from one CAA set, and that is not a bug. apache.org permits Let’s Encrypt at the apex and forbids it at www, from the same effective records and the same issuer. The apex is served a non-wildcard certificate, judged against issue, while www.apache.org is served *.apache.org, judged against issuewild, and the zone publishes issuewild "ssl.com" only. When two hosts disagree, check whether the served certificate is a wildcard before concluding the verdict is wrong.
tlsa
| Key | Meaning |
|---|---|
apex, www | _443._tcp TLSA records as published |
signed | The TLSA answers, positive or negative, were DNSSEC-validated. In a signed zone this is true even with result: none, because the denial itself is signed |
result | none (looked up, no TLSA records exist), match, mismatch, unverified, unknown (the lookup did not complete, so whether DANE is configured is unknown; signed is false because nothing was validated) |
A domain where nothing could be determined
On 2026-09-07, while its nameservers were down, microsoft.jp.net fired every not-determined path at once. An earlier build asserted from those four failed lookups that it publishes no DMARC record, that any CA may issue for it, that it has no DANE, and that it has no wildcard. The same outage now yields mail.dmarc.unresolved, caa.hosts.*.permitted absent, tlsa.result: "unknown" and wildcard.status: "unknown", while still failing on what was actually observed: nameservers answering nothing, and www lookups timing out. Four confident negatives became four honest unknowns without losing a single real error.
Its nameservers have since recovered, so probing it today returns ordinary answers. That is the nature of live examples, and the reason this one is dated.
wildcard
Whether the zone answers names that were never published, tested by looking up random 12-letter labels.
| Key | Meaning |
|---|---|
status | present (three random names all answered), absent (one was definitively denied, or an answer already in hand settled it, such as www NXDOMAIN), unknown (a probe never came back) |
determined_by | Why the verdict was reached, in words: 3 random names all answer, the random name qhrmzvbxklap is denied |
probes | One entry per random name actually issued: label, status (answered, denied, unresolved), addresses, optional cname. Its length is how much evidence the verdict rests on: 0 when an answer was already in hand, 1 when the first name was denied, 3 for a confirmed wildcard |
addresses | What the wildcard answers with, when there is one |
consistent | null unless status is present; true when all three probes returned the same addresses and CNAME |
www_via_wildcard | www resolves to exactly the wildcard’s addresses, so it is a catch-all answer rather than a real host |
unknown is the reason this is a tri-state. A single present: false previously covered NXDOMAIN, NODATA, timeout and failure alike, so a lookup that quietly failed was indistinguishable from a clean zone. Do not render unknown as false.
A wildcard on its own raises no warning; only www_via_wildcard produces one. It is data to score, not a fault. consistent: false is worth scoring separately, since a catch-all that rotates its answers is a different shape from a stable one.
Enumerations
| Field | Values |
|---|---|
dns.*.*.status | ok, nxrrset, nxdomain, failure, timeout |
dns.*.*.trust | secure, insecure, bogus |
dns.resolver_reachable.* | yes, no, skipped: resolver has no <family> address |
dnssec.state | secure, insecure, island (DNSKEY but no DS), bogus, servfail, unknown |
delegation.status | match, mismatch, not_delegated, no_child_answer, same_servers, child_no_ns, not_a_zone, error |
web.*.*[].80 / .443 | open, refused, timeout, unreachable, error, skipped |
web.*.*[].tls.chain | valid, expired, not_yet_valid, hostname_mismatch, self_signed, incomplete_chain, untrusted_root, invalid, handshake_failed |
web.*.*[].tlsa | match, mismatch, none |
tlsa.result | none, match, mismatch, unverified, unknown |
hsts_preload | preloaded, absent, unknown |
wildcard.status | present, absent, unknown |
wildcard.probes[].status | answered, denied, unresolved |
redirects.*.ended | final, external, loop, hop_limit, error |
Generated from the live server (DataPulse MCP 1.0.0) on October 1, 2026. Your AI assistant reads this page by calling datapulse_help(topic="domain_health_fields").