How the score is calculated
Every deduction on a dotvitals report comes from a published rule with a published weight. This page is generated from the same configuration the scoring engine runs, so it cannot describe a formula we no longer use.
Scoring configuration 2026.10.1 · ruleset 2026.10.12.32 ·301 rules
The shape of it
Each category starts at 100. Every failing or warning check subtracts its rule's published deduction, scaled by how sure we are and by how many times the same fault repeats, and bounded by a ceiling on the family of related faults it belongs to. The overall score is the weighted mean of the categories we were able to measure, with a handful of faults severe enough to cap it outright.
categoryScore = min(max(0, 100 − Σ_families min(familyCap, Σ_findings
deduction × statusMultiplier × confidenceMultiplier × repeatMultiplier)),
gateCap, verificationCeiling(verifiedShare))
verifiedShare = Σ_modules (1 − priced gaps) / Σ_modules (1 − unpriced gaps)
each module's gaps sized and classified by the module itself
overall = min( Σ weight × categoryScore / Σ weight , gateCap )
over the categories that were actually measuredNothing is hidden behind that. Open any finding on a report and it shows the rule, the deduction, the multipliers that were applied and the cap it landed under; the numbers in the drawer add up to the number printed next to it, and a test proves they do.
Category weights (95 points of scope)
The weights are a product judgement about what matters to a domain owner — explicit, versioned, and written down here so you can disagree with a specific number rather than with a black box. They are not derived from a risk calculation, and we do not claim they are. Internet.nl, the only comparable tool covering more than one domain of risk, avoids the question by keeping its web and mail scores separate rather than blending them; we blend them, and the weights below are where that choice is visible.
| Category | Weight | Share | Rules | What it covers |
|---|---|---|---|---|
| Email authentication | 15 | 15.8% | 41 | SPF, DKIM, DMARC and BIMI — whether a receiving mail server can tell your mail from a forgery. |
| Email transport | 8 | 8.4% | 33 | MX records, STARTTLS, MTA-STS, TLS reporting and reverse DNS — whether mail reaches you, encrypted. |
| Email reputation | 5 | 5.3% | 5 | Whether the domain or its mail servers appear on a blocklist we can query. |
| DNS | 10 | 10.5% | 38 | The records the zone publishes, the delegation behind them, and whether every nameserver agrees. |
| DNSSEC | 4 | 4.2% | 14 | Whether the zone is signed, whether the chain validates, and how it is parameterised. |
| Domain registration | 5 | 5.3% | 12 | Registration, expiry, registrar and registry locks — whether you still control the name. |
| TLS | 15 | 15.8% | 26 | The certificate, its chain and expiry, and which protocol versions and ciphers are offered. |
| HTTP | 7 | 7.4% | 26 | Whether the site answers at all, how it redirects, and how it serves what it returns. |
| Web security | 8 | 8.4% | 43 | Security headers, cookie attributes, CSP, CORS and framing — the browser-side controls. |
| Network | 5 | 5.3% | 6 | Ports answering the public internet that should not be. |
| Performance | 8 | 8.4% | 23 | Field data from real Chrome users, plus the lab opportunities that explain a slow page. |
| SEO | 5 | 5.3% | 33 | Indexability first, then canonicals, metadata, crawl directives and structured data. |
| Reputation | 0 | 0.0% | 0 | Whether the domain itself is known for phishing, malware or abuse. Weighted 0 and not scored: every free source that could answer this is licensed against commercial use, so rather than score you on a question we never asked, we say plainly that we did not ask it — see the email reputation section for the full list and the reasons. |
| Technology | 0 | 0.0% | 1 | The software we can identify behind the site. Measured and reported, never scored — see below. |
Reputation is weighted 0 on purpose. It is measured and reported, not scored — its findings are already scored under web security, so giving it a weight would count them twice, and we do not grade software we identified by inference. Lighthouse does the same thing with Time to Interactive and INP: weight 0, still measured, still shown. A zero weight here means "deliberately not graded", never "not bothered with".
Technology is weighted 0 on purpose. It is measured and reported, not scored — its findings are already scored under web security, so giving it a weight would count them twice, and we do not grade software we identified by inference. Lighthouse does the same thing with Time to Interactive and INP: weight 0, still measured, still shown. A zero weight here means "deliberately not graded", never "not bothered with".
How one finding becomes a deduction
A rule declares a deduction — how much it removes from its category's 100. Three multipliers stand between that number and the score.
Status: did the check fail, or merely warn?
| Status | × | Meaning |
|---|---|---|
| fail | 1 | The check failed. The rule's full deduction applies. |
| warn | 0.5 | The check found something worth changing but not broken. Half the deduction applies. |
| pass | 0 | The check passed. Nothing is deducted. |
| info | 0 | A fact worth reporting that is neither good nor bad. Nothing is deducted. |
| error | 0 | The check could not run. Nothing is deducted — and the category is marked incomplete rather than passed. |
| skipped | 0 | The check was not attempted. Nothing is deducted, and again the gap is reported rather than scored. |
Confidence: how sure are we?
| Confidence | × | Meaning |
|---|---|---|
| confirmed | 1 | We read it directly — from a record, a response or a handshake we performed. |
| high | 1 | Strong evidence, short of reading the thing itself. |
| medium | 0.5 | Inferred from evidence that usually means this, such as a selector found by guessing a common name. |
| low | 0.25 | A weak signal. It is still reported, but it moves the score by a quarter of the rule's weight. |
This one is ours, and nobody else does it. We benchmarked the scoring model against Mozilla Observatory, Qualys SSL Labs, Internet.nl and Lighthouse. None of them grades its own certainty: a check either counts in full or is excluded. Scaling a deduction by confidence is a dotvitals mechanism with no external precedent, so treat it as our judgement rather than as an inherited convention.
The reasoning is that there are two different kinds of "we are not sure". When a probe fails, nothing was learned, and the right answer is to exclude the check entirely — which is what the error and skipped statuses above already do. When a DKIM selector is found by guessing a common name, or a technology is inferred from a header, something was learned. Discarding it would systematically flatter the domains whose problems happen to be hard to confirm. Discounting it keeps the finding visible and keeps its weight proportionate to the evidence.
Where a confidence level comes from is published as well, not only what it multiplies by. For technology detection — the one category that is inference from end to end — every fingerprint names the vendor document, standard or dated observation it was written from, and you can read all of them: technology fingerprint provenance.
Repeats: the same fault, several times
When one rule fires more than once — the same weak cipher on four ports, the same missing attribute on six cookies — the instances are ordered heaviest first and tapered.
| Instance | × |
|---|---|
| 1st | 1 |
| 2nd | 0.5 |
| 3rd and every one after it | 0.25 |
Ordering by weight rather than by the order modules happened to report in is what makes the score independent of scan timing, and what makes "adding a failing check can never raise the score" true.
Family caps
Related rules share a ceiling. Without one, a single underlying problem that produces many findings would outweigh everything else on the report: a host with MySQL, PostgreSQL and Redis all answering the internet has one problem — no firewall — and must not be scored as though it had three, and six SOA timer complaints are one piece of DNS hygiene, not six outages.
Each cap is sized on one rule and one heuristic. The rule: no single family may take its category to zero on its own. The heuristic: the cap sits at or a little above the family's heaviest single rule, so the fault that matters most still lands at its full published weight, and at or below the family's summed deductions, so the cap can actually bind. Both bounds are asserted by a test, and the columns below let you check them yourself.
All 56 family caps
| Family | Cap | Rules | Heaviest rule | If all fired |
|---|---|---|---|---|
| dns.health.delegation | 35 | 6 | 20 | 71 |
| dns.health.exposure | 25 | 2 | 20 | 28 |
| dns.health.redundancy | 20 | 3 | 12 | 25 |
| dns.health.soa | 20 | 5 | 15 | 23 |
| dns.health.transport | 8 | 1 | 8 | 8 |
| dns.health.zone | 20 | 2 | 12 | 20 |
| dns.propagation.consistency | 25 | 2 | 20 | 32 |
| dns.propagation.ttl | 4 | 1 | 4 | 4 |
| dns.records.address | 30 | 2 | 25 | 40 |
| dns.records.caa | 15 | 3 | 10 | 18 |
| dns.records.ttl | 6 | 2 | 3 | 6 |
| dns.records.txt | 12 | 2 | 6 | 12 |
| dnssec.chain | 50 | 2 | 45 | 70 |
| dnssec.keys | 20 | 2 | 12 | 22 |
| dnssec.nsec3 | 9 | 2 | 5 | 9 |
| dnssec.signatures | 55 | 3 | 50 | 90 |
| domain.expiry | 90 | 5 | 90 | 360 |
| domain.lifecycle | 90 | 1 | 90 | 90 |
| domain.locks | 30 | 2 | 25 | 35 |
| email-auth.bimi | 10 | 4 | 6 | 21 |
| email-auth.dkim | 30 | 7 | 25 | 102 |
| email-auth.dmarc | 40 | 9 | 25 | 122 |
| email-auth.spf | 35 | 17 | 35 | 260 |
| email-reputation.blocklists | 80 | 2 | 40 | 80 |
| email-transport.mta-sts | 25 | 8 | 12 | 71 |
| email-transport.mx | 30 | 8 | 30 | 100 |
| email-transport.rdns | 25 | 4 | 20 | 41 |
| email-transport.smtp-tls | 40 | 8 | 30 | 143 |
| email-transport.tls-rpt | 10 | 3 | 4 | 12 |
| http.caching | 12 | 3 | 6 | 15 |
| http.compression | 18 | 4 | 8 | 23 |
| http.content-type | 12 | 2 | 10 | 14 |
| http.hygiene | 10 | 2 | 8 | 11 |
| http.reachability | 60 | 5 | 60 | 110 |
| http.redirects | 45 | 7 | 40 | 133 |
| network.exposure | 60 | 3 | 40 | 82 |
| performance.assets | 25 | 5 | 8 | 30 |
| performance.field | 35 | 5 | 12 | 48 |
| performance.render | 10 | 1 | 10 | 10 |
| seo.canonical | 20 | 3 | 15 | 31 |
| seo.content | 15 | 3 | 8 | 18 |
| seo.crawl | 15 | 4 | 8 | 22 |
| seo.i18n | 8 | 4 | 6 | 19 |
| seo.indexability | 45 | 4 | 35 | 95 |
| seo.meta | 20 | 6 | 12 | 33 |
| seo.social | 5 | 1 | 5 | 5 |
| seo.structured-data | 10 | 2 | 8 | 13 |
| tls.certificate | 60 | 15 | 60 | 424 |
| tls.protocols | 40 | 9 | 60 | 258 |
| web-security.cookies | 30 | 8 | 15 | 85 |
| web-security.cors | 35 | 8 | 30 | 93 |
| web-security.csp | 30 | 7 | 22 | 62 |
| web-security.disclosure | 10 | 3 | 5 | 11 |
| web-security.framing | 12 | 1 | 12 | 12 |
| web-security.headers | 20 | 5 | 8 | 30 |
| web-security.hsts | 28 | 3 | 25 | 38 |
A rule that declares no family stands alone and is bounded only by the category's default ceiling of 100. That is reserved for rules that cap a category outright anyway — the gates below.
Gates: when one fault is the whole story
A weighted mean cannot express "this one thing is so wrong that nothing else matters". TLS is 15.8% of the scope, so a domain serving an expired certificate would still score in the eighties on the strength of its DNS and its mail. Gates are the override that makes the mean safe: a small set of faults that cap the score outright, whatever else is right.
TLS certificate expired, mismatched or untrusted
Caps the overall score at 40 and TLS at 40. Fires only at high confidence or above.
Domain or mail IP listed on a blocklist
Caps the overall score at 30 and Email reputation at 30, Reputation at 30. Fires only at confirmed confidence or above.
DNSSEC chain is broken (SERVFAIL on validating resolvers)
Caps the overall score at 30 and DNSSEC at 30, DNS at 30. Fires only at high confidence or above.
Domain registration expires in under 7 days
Caps the overall score at 50 and Domain registration at 50. Fires only at high confidence or above.
Each gate caps its own category as well as the overall score, so a category panel can never show a comfortable number while the summary it belongs to is gated — the drill-down would otherwise contradict the headline. And a gate never fires on a guess: the confidence floor is on every one of them, because capping somebody's score at 30 on an inference is not something we could defend to them.
Grades
| Grade | Overall score |
|---|---|
| A+ | 95 and above |
| A | 90–94 |
| B | 80–89 |
| C | 65–79 |
| D | 50–64 |
| F | 0–49 |
These bands are reasoning rather than measurement, and that is worth saying plainly. Comparing them to Observatory's or SSL Labs' bands directly would be misleading — a threshold means nothing without the aggregation function under it, and ours is a weighted mean of fourteen categories, which regresses toward the middle where a running penalty total does not. Once there is a large enough body of real scans, we intend to plot the distribution and move the boundaries if they do not separate meaningfully. We would not move the weights to fix a distribution.
A+ has to be earned, not merely not-lost
A+ needs the score, and no finding at high severity or worse, and every applicable item below demonstrated affirmatively. The old rule was two absences — a high enough score and no serious complaints — which meant a domain that did everything adequately and nothing well could reach the top grade. Both comparable tools that award a top grade require an affirmative extra, and so do we.
| Required | Applies to | Minimum confidence |
|---|---|---|
| DMARC published at p=quarantine or p=reject | Email authentication | confirmed |
| HSTS with a max-age of at least six months | Web security | confirmed |
| TLS 1.3 supported | TLS | confirmed |
Each is decided by the check you can already see on the report — DMARC is enforcing, so spoofed mail is quarantined or rejected, The HSTS instruction lasts six months or more, The server supports TLS 1.3 — rather than by a second, invisible test. The grade and the finding can therefore never disagree.
Missing an A+ prerequisite withholds A+ and nothing else: the domain gets an A. These decide whether the top grade is awarded; they never deduct. And within a category we did scan, silence is not credit — if the HSTS check did not produce a pass, for any reason including an error, the achievement was not demonstrated. A category that was never in the scan at all is simply not applicable: a mail-only scan has no opinion about HSTS, and denying A+ for evidence nobody asked us to gather would make the grade depend on which tool page you arrived through rather than on the domain.
What we will not score
The most important part of a scoring model is what it does when it does not know. A methodology page that lists weights without describing the denominator is describing a different engine.
A category we could not test is excluded, never assumed to pass
If the TLS checks did not run, TLS does not score 100 and it does not score 0. It leaves the calculation, and the weighted mean is taken over the categories that remain. Scoring it 100 is a false pass; scoring it 0 penalises a domain for our probe being down; keeping it in the denominator at 0 points is arithmetically the same as scoring it 0. Excluding it is the only honest answer, and it is why a report will tell you "TLS was not tested" instead of showing you a green panel.
A score built on part of the assessment is labelled as one
Renormalising gives the surviving categories more influence than they would otherwise have, so a partial score is not comparable to a complete one and is never presented as though it were. Any scan with an untested or partly verified category is markedpartial, and its grade is capped according to why the gap is there — the same principle as the A+ prerequisites, extended downward: a top grade is awarded for a demonstrated positive, and a check nobody ran is precisely an absence of evidence.
When the missing part is a limit on our side — the Chrome UX Report publishes no data for your site, a test only a verified owner can run, a sample we deliberately stop at, such as the number of addresses a port check connects to — the scan cannot be graded above A. A+ needs a complete assessment, and your site did nothing to lose A. When the site caused the gap — a timeout, a refused connection, an error or challenge page, an address we may not connect to — the scan cannot be graded above B, and the report says what failed. So can a gap our own run left, such as our probe host being unreachable, or a source we read — a domain registry, the Chrome UX Report — not answering at all: it is not a limit we chose, another scan may close it, and a grade that rose because of our outage would be the false pass this rule exists to prevent. The report says which it was and never blames your site for ours. Where there is more than one gap, the strictest cap wins.
The report names each test that is missing because of a limit on our side, and says that waiting or running the same scan again will not fill it. Where the missing test is one only a verified owner can run — the in-browser speed test — it offers the verification, and says plainly that verifying adds that test without lifting the cap by itself while any other test is still missing.
A report scored before 2026-10-12 recorded no cause and keeps the cap it had: no higher than B for a category not tested at all, and no higher than A for one that left a gap inside a category it did test.
A check we could not run puts a ceiling on its category's score
This is the part most scoring models get wrong, including ours until 2026-09-21. Every other lever above scales a deduction — and a check that passed, or that never ran at all, deducts nothing. Multiplying zero by any confidence is still zero, so a category whose port scan half-finished, or whose blocklist question could not lawfully be asked, went on reporting 100 / A+. The correction never reached the number.
So verification is applied as a ceiling on the score rather than as a deduction from it. Each check that ran reports, itself, what it could not verify and how much of its subject that was — a network of yours nothing connected to, two protocol versions of six never offered, one question of two with nowhere to ask it. Those shares are what the ceiling is priced from. The module knows the size of the hole it left; a scoring layer that charged every incomplete check the same flat fraction did not, and until 2026-09-21 ours charged a category by how many checks it happened to contain rather than by how much of it went unseen. Where the verified share is short of complete, the category's score may not exceed 94, falling a further 40 points in proportion to how much is missing, and never below 80 — a gap in the evidence costs a band or two, never a collapse. A category whose checks produced no result for less than 60% of them is withheld rather than capped.
A ceiling, not a deduction, because the two say different things. A deduction would appear in your breakdown as a fault of your domain, and our probe host being unreachable is not one. A ceiling says the true thing: what we saw is fine as far as it goes, and it does not go all the way. Every capped category names the gap in the module's own words — which address, which version, which file — so it is something you can read rather than something you have to infer from a number.
What we did not connect to is measured, not assumed
The port check connects to every address your domain publishes, up to eight IPv4 and eight IPv6, because two addresses of one name can be two machines with two firewalls, and the IPv6 one is the firewall most often forgotten. Each address gets the same five connections at a time it always did. It stops at eight in a family rather than connecting to every address you could publish, because a name can publish dozens and knocking on all of them is a great deal of traffic to send at one estate for one report. Where a family has more than eight, the eight are picked at random for each scan, so there is no address every scan skips. That stopping point is a limit of ours, so on its own it never holds the overall grade below A. It is still a gap in what we saw, though: the addresses it leaves out can lower the Network score, as the next paragraph explains.
On a domain publishing more than that, it leaves the rest of a family, and we will not tell you they are fine because they are probably the same machine. We check instead: if an address we did not connect to is in the same routed network as one we did — the same /24 or /48, reached through the same routing announcement — we say so and name the network, and it costs your score nothing, because the evidence is there for you to judge. If it is in a network nothing reached, that is a real gap, it is charged, and we name it. If we cannot place it at all, we say that too rather than rounding it into either answer. It is worth knowing which way we err: two machines of yours in two different networks are treated as two, so you may see a gap reported for addresses that are in practice identical. We would rather understate what we covered than overstate it.
Three kinds of gap are stated but not charged
A gap that another scan could close — a timeout, a resolver that did not reply, a network our budget did not reach — is charged in full: your domain has a state there that we did not see. A gap that no scan of ours can close is different. SSL 2.0 and SSL 3.0 cannot be offered by the TLS library we handshake with; whether your domain is on a domain-level reputation list has no source we are licensed to ask. Charging those would cap every domain identically, forever, and a ceiling that binds on every scan measures the scanner rather than the domain and tells you nothing about yours. So they are excluded from the share above and stated beside the score instead, every time, in the check's own words — never folded into a pass, and never silently dropped.
The third is not a shortfall of ours at all: a question your domain does not pose. A domain that publishes no mail servers has no mail transport to secure and no mail reputation to look up, and until 2026-09-22 we marked it down for it — the reputation area was withheld for "low coverage", which pulled the whole scan's grade to no better than B. An area with no subject is now taken out of the score's scope rather than withheld inside it: it is not counted as passing, it is not counted as failing, it is not counted as untested, and it does not shrink the share of the assessment we say we measured. The page tells you which areas did not apply, so you can see that we looked and found nothing there to check.
| Kind | Charged | What it means |
|---|---|---|
unanswered — Did not answer | in full | We asked and got no usable answer — a timeout, a refused connection, a resolver that did not reply, a data source with nothing for this name. Another scan may close it. |
limited — Stopped short | in full | We stopped at our own limit — eight addresses of more in one family, a byte cap, an element cap. Your domain has a state there that this scan did not see. |
capability — Cannot test yet | stated only | No run of this scanner can currently ask the question; SSL 2.0 and SSL 3.0 are the case, because the TLS library we handshake with is built without them. Stated beside the score, not charged against it. |
no-source — No source exists | stated only | No data source we may use exists for the question — the domain-level reputation lists are all licensed against commercial use. Stated beside the score, not charged against it. |
not-applicable — Does not apply here | stated only | There is no question to ask about your domain — it publishes no mail servers, so it has no mail transport and no mail reputation. Nothing is missing from the report: an area that does not apply leaves the score's scope altogether rather than being withheld, which is what used to hold a domain with no mail to a B. |
| Module state | Credit | What it means |
|---|---|---|
ok | 1 | The module ran and answered every question it was asked. |
not-applicable | 1 | The module determined this check does not apply to this target. That is a verdict. |
partial | 0.75 | The module ran and left a stated hole. A live scan prices the hole from the module's own account of its size (the table above); this flat fraction applies only to a scan stored before the modules reported one. |
error | 0 | The module failed. We know nothing about this check. |
timeout | 0 | The module ran out of time. Same: we know nothing. |
skipped | 0 | The module was never dispatched, or its dependencies never arrived. |
Below half the scope, we state no score at all
When less than 50% of a scan's scoped weight was actually measured, no overall score is shown. A number derived from a fifth of the checks is a number about a fifth of the domain, and presenting it as the domain's score is the same false pass in a different place. Within a single category the same floor applies at 60% coverage: below it the category reports "incomplete" rather than a figure.
A score is comparable within one ruleset version, and not across two
Every scan stores the scoring configuration and ruleset version it was scored under — today 2026.10.1 and 2026.10.12.32. Changing a weight, a cap or a rule's text changes what a number means, so we bump the version rather than quietly re-baselining history. When you compare two scans of the same domain, the comparison tells you which differences are your configuration changing and which are ours — because a score that moved because we changed our mind is not an improvement, and reporting it as one would be the easiest lie on the whole report.
How the statistics on rule pages are measured
A rule page may carry one line under its heading — "23% of the domains we could check fail this" — and this section is where that number comes from: which domains, which checks, what was done with the domains that could not be checked, and why some rules show no figure at all.
The figures shown today come from the first 1,000 domains by rank in the Majestic Million, downloaded on (SHA-256 of the file: 058561690acfdb2689b67308381f9a65085c751f063dd98b62b0e68eb3c01982), and checked on under ruleset 2026.10.12.32. Of 1,000 domains, 949 were checked, 51 were refused by our egress guard before any check was made, and on 125 the request budget below stopped at least one check.
The sample, and its licence
The domains are the first 1,000 of the Majestic Million by rank — Majestic's free, daily list of the domains with the most referring subnets on the web — published under CC BY 3.0, which permits commercial use with attribution. We chose it over the other public rankings because its licence is the only one of them without a non-commercial component. The list is not redistributed here: we record the day the file was downloaded and the SHA-256 of its bytes, and print both above once a sweep is published, so anyone can confirm which list a figure came from.
A domain on this list is not necessarily a website. The ranking is by how many networks link to a domain, so the top of it holds, beside the sites a reader would expect, the domains that infrastructure lives on: CDN and asset hostnames, API endpoints, link shorteners, mail and tracking domains. Every figure is a share of domains, and a rule about a web page is measured over the domains that served one.
Which checks run
The sweep is passive. It reads the records a domain publishes, and whether each of its mail servers' addresses has a reverse name, through public resolvers over DNS-over-HTTPS; makes one plain-HTTP and one HTTPS request to the home page to see where the site sends a visitor and what the landing page's headers say; and opens one TLS connection on port 443, with no request on it, to read the certificate. The checks are the product's own modules — the same code, the same verdicts a report shows — and nothing that probes a site more actively than a browser's first visit runs at all.
| Module | Id | What it reads |
|---|---|---|
| Dns records | dns.records | Record sets, CAA and the wildcard check, read through a public resolver only. The authoritative column needs a query to the zone's own servers and is left unfilled, so the checks that depend on it are counted as not checked. |
| Email mx | email.mx | MX records, the addresses behind them, and one reverse (PTR) lookup per address to see whether it has a name at all, all from a public resolver. |
| Email spf | email.spf | The SPF record and the records it includes, from a public resolver. |
| Email dmarc | email.dmarc | The DMARC record, from a public resolver. |
| Email mta sts | email.mta-sts | The MTA-STS record, and the policy file at the mta-sts host when the record exists. |
| Email tls rpt | email.tls-rpt | The TLS-RPT record, from a public resolver. |
| Email bimi | email.bimi | The BIMI record, and the logo it points at when the record exists. |
| Http reachability | http.reachability | One plain-HTTP and one HTTPS request to the home page, neither followed: does the site answer, and does port 80 send a visitor to HTTPS. |
| Http redirects | http.redirects | The redirect chain from http://<domain>/, each hop a separate request within the budget below. |
| Web security headers | web.security-headers | The security headers on the page the chain ends at. No extra request: it reads the response the chain already fetched. |
| Web cookies | web.cookies | The cookies set by that same final response. No extra request. |
| Tls certificate | tls.certificate | One TLS handshake on port 443, with no HTTP request on it, for the certificate the site presents and whether it verifies. |
The checks that do not run, and why
| Module | Id | Why |
|---|---|---|
| Dns health | dns.health | Needs queries sent to each of the zone's own nameservers, not to a public resolver. |
| Dns dnssec | dns.dnssec | Needs DNSKEY and DS answers from the zone's own servers and a sweep of validating resolvers; there is no passive version of the check. |
| Dns propagation | dns.propagation | A query to a dozen public resolvers per domain, which is a dozen times the traffic of every other DNS check. |
| Domain rdap | domain.rdap | A registry query per domain, which is traffic to registries rather than a reading of the domain. |
| Email dkim | email.dkim | A DKIM key is published under a selector the sweep cannot know. |
| Email rdns | email.rdns | The deeper reverse-DNS checks: whether each mail server's reverse name resolves back to the same address, and whether it looks like a name a provider minted for a whole subnet. Those say more about the mail provider than about the domain. Whether an address has a reverse name at all is counted, under email.mx above. |
| Email smtp tls | email.smtp-tls | An SMTP conversation on port 25 with the domain's mail servers. |
| Email blocklists | email.blocklists | A query to each blocklist operator per mail server address. |
| Http headers | http.headers | Two more requests to the home page, with different Accept-Encoding values. |
| Web cors | web.cors | Requests carrying a foreign Origin header, and an OPTIONS preflight. |
| Web technology | web.technology | Reads the page body for fingerprints, which is a different question from whether the domain is configured safely. |
| Seo audit | seo.audit | Fetches robots.txt and a sitemap as well as the page. |
| Perf crux | perf.crux | A third-party API query per domain. |
| Perf assets | perf.assets | Fetches a sample of the page's subresources. |
| Perf lab | perf.lab | A rendered page in a real browser. |
| Tls protocols | tls.protocols | Up to forty handshakes per host to enumerate protocol versions and cipher suites. |
| Net ports | net.ports | A connection attempt on every port in the scan list. |
| Net reach smtp | net.reach-smtp | A connection attempt on port 25 to each mail server address. |
| Net reach dns | net.reach-dns | A connection attempt on port 53 to each nameserver address. |
| Reputation | reputation | Carries no checks today; there is nothing to run. |
What "could not check" means, and where it goes
Every domain lands in exactly one of five buckets for every rule: pass, warn, fail, could not check or not applicable. A domain could not be checked when our egress guard refused it (a name resolving to a private or reserved address is never fetched), when a module failed or ran out of time, when the module itself reported the check as a gap, or when the request budget below stopped a check before it ran. A check is not applicable when it had nothing to judge — a mail check on a domain that publishes no mail servers. Neither is a failure. The percentage on a rule page is taken over the pass, warn and fail buckets only, and the number of domains it was taken over is printed in the sentence.
The floor
A figure is shown only when at least 200 of the sample could be checked for that rule. At that size the sampling error on a percentage is at most about seven points, which is the most a figure printed to the nearest whole percent can honestly carry; and a rule checkable on fewer than one domain in five would be a statistic about whichever fifth happened to be checkable. Below the floor the page says nothing rather than something small. A rule that cannot fail or warn — one that reports a fact — carries no figure either.
How politely it is done
One domain's checks send at most 1 plain-HTTP and 1 HTTPS request to each hostname they reach; a redirect to another hostname is followed under the same limit, and a chain that would need more is stopped and counted as not checked rather than guessed at. Every request carries the published User-Agent, whose URL is the page that says what this is and how to opt out. Mail-authentication and DNS records are read from public resolvers, never from a domain's own servers, and DKIM is not checked at all: a key is published under a selector the sweep has no way to know.
Attribution
Domain list: Majestic Million, published by Majestic, used under CC BY 3.0. The counts are ours; nothing about any individual domain is published, and the per-domain results of a sweep are kept only long enough to review the counts.
Every rule, in the open
All 301 rules are published with their severity, deduction, family cap and the standards they cite.
Browse the rule catalogue