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.09.6 · ruleset 2026.09.9 ·292 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 = max(0, 100 − Σ_families min(familyCap, Σ_findings
deduction × statusMultiplier × confidenceMultiplier × repeatMultiplier))
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% | 40 | 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% | 25 | The certificate, its chain and expiry, and which protocol versions and ciphers are offered. |
| HTTP | 7 | 7.4% | 25 | Whether the site answers at all, how it redirects, and how it serves what it returns. |
| Web security | 8 | 8.4% | 42 | 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% | 18 | 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 | 16 | 35 | 252 |
| email-reputation.blocklists | 80 | 2 | 40 | 80 |
| email-transport.mta-sts | 25 | 8 | 12 | 71 |
| email-transport.mx | 30 | 8 | 30 | 103 |
| 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 | 4 | 60 | 105 |
| http.redirects | 45 | 7 | 40 | 133 |
| network.exposure | 60 | 3 | 40 | 82 |
| performance.assets | 25 | 5 | 8 | 35 |
| 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 | 6 | 22 | 58 |
| 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 partially tested category is markedpartial and cannot be graded above B— the same principle as the A+ prerequisites, extended downward: a top grade is awarded for a demonstrated positive, and a category nobody looked at is precisely an absence of evidence.
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.09.6 and 2026.09.9. 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.
Every rule, in the open
All 292 rules are published with their severity, deduction, family cap and the standards they cite.
Browse the rule catalogue