Outrings
Methodology

Every check, explained.

All 200 checks across 18 categories, exactly as the engine runs them. If you disagree with a rule, you can see precisely what it measures and decide for yourself whether the verdict is fair.

200
individual checks
18
weighted categories
0
third-party services used
0
language models involved

The pipeline

1 — One fetch pass

A single collector fetches the page, follows and records the redirect chain, then gathers robots.txt, sitemaps, llms.txt, security.txt, the well-known paths, discovered policy pages and a bounded set of linked pages. Strict timeouts, a 3 MB response cap, a redirect cap and a global per-audit budget apply to every request.

2 — Parse, never execute

HTML is parsed into a document tree in tolerant mode, the way a browser would recover from broken markup — but no JavaScript ever runs. What you see scored is what the server actually sent, which is also what crawlers and AI retrieval systems see.

3 — Eighteen pure modules

Each category is a pure function: it receives the collected artefacts and returns {score, weight, checks[]}. Modules never fetch anything themselves, so a category cannot influence another, and results are reproducible.

4 — Deterministic scoring

Nothing is sampled randomly, no model judges anything, and no result depends on the time of day. The same page produces the same score every time.

How the score is calculated

There is no secret formula. It is two weighted averages, in this order.

Step 1 — each check becomes a value

A pass is worth 1.0, a warning 0.5, a failure 0. Checks marked info or not applicable are excluded from scoring entirely — a site is never punished for a check that does not apply to it.

Step 2 — each category is a weighted mean of its checks

category score = Σ(check value × check weight) / Σ(check weight) × 100

Step 3 — the overall score is a weighted mean of categories

overall = Σ(category score × category weight) / Σ(category weight)

Because the whole thing is a weighted mean, the points any single unresolved check is costing you can be worked out exactly — which is how the recommendations put a precise number on each fix rather than an estimate.

How certain each result is

Every check carries a classification so nothing has to be taken on equal trust: measured was observed directly in a response, derived was computed deterministically from observations, and inferred is a heuristic that can be wrong. Anything sourced from a third party would be external — nothing currently is.

A check that reaches no verdict says which kind of no: unknown (we looked and could not tell), blocked (the target refused), timeout, inconclusive, or requires_browser (would need JavaScript we deliberately do not run). None of these are scored, and none of them should ever be read as a pass. Every report states its coverage: the share of checks that reached a verdict at all.

Category weights

CategoryWeightChecksWhat it affects
SEO 1.4 21 Search visibility, Click-through rate, Crawl efficiency
Local & Regional 0.7 8 Local search, Map results, Regional targeting
AI Visibility 1.2 21 AI answers, Citations, Retrieval quality, Generative search
DNS & Email 0.9 10 Reachability, Email deliverability, Domain spoofing, Resilience
TLS & Certificate 1.1 10 Browser trust, Availability, Data integrity, SEO
Security 1.3 18 User safety, Data integrity, Browser trust, Liability
Privacy & Policies 0.9 7 Legal compliance, User trust, Regulatory risk
Infrastructure 0.9 11 Page speed, Core Web Vitals, Hosting cost, Reliability
Tech Stack & APIs 0.8 9 Page speed, Supply-chain risk, Maintainability
Content Quality 1 10 Engagement, Dwell time, Conversion, Perceived expertise
AI-Slop Detector 0.8 8 Credibility, Ranking risk, Brand perception
Design & UX 0.9 10 Mobile usability, Accessibility, Core Web Vitals, Conversion
Accessibility 1 16 Disabled users, Legal exposure, SEO, Usability for everyone
Credibility & Honesty 0.9 8 Trust, Conversion, Regulatory exposure
Title-Content Match 0.8 7 Bounce rate, Click-through rate, Ranking stability
FAQ & Questions 0.7 7 Featured snippets, AI answers, Long-tail search
Discoverability 1 11 Indexation, Crawl budget, New-page discovery
Contact & Exposure 0.7 8 Trust, Lead capture, Spam exposure, Compliance

Grades

A+ is 95 and above, then A at 90, A− 85, B+ 80, B 75, B− 70, C+ 65, C 60, C− 55, D+ 50, D 45, D− 40, and F below 40.

Every check

SEO weight 1.4 · 21 checks

SEO decides whether people can find the page at all. Metadata and structure control how the page is indexed, and how it is described in the result that decides whether anyone clicks.

If ignored: The page either never surfaces for relevant queries, or surfaces with a machine-written snippet that undersells it.

seo.alt
Image alt text · weight 1.2 · fix takes hours
Tests: alt attribute coverage
Why: Most images carry no textual equivalent.
seo.anchors
Anchor text consistency · weight 0.6 · fix takes hours
Tests: Same anchor pointing at different URLs
Why: Reusing one phrase for several destinations muddies the relevance signal.
seo.anchortext
Descriptive anchors · weight 0.6 · fix takes hours
Tests: Empty or generic link text
Why: Anchors describe their destinations.
seo.canonical
Canonical URL · weight 1.2 · fix takes minutes
Tests: Presence of rel=canonical
Why: Conflicting canonicals are ignored outright.
seo.description
Meta description · weight 1.5 · fix takes minutes
Tests: Presence and length of meta description
Why: The description fits the snippet without truncation.
seo.h1
H1 heading · weight 1.5 · fix takes minutes
Tests: Count of <h1> elements
Why: The H1 states the page topic for both readers and crawlers.
seo.hierarchy
Heading structure · weight 1 · fix takes hours
Tests: Heading level sequence
Why: Skipped levels break the document outline.
seo.hreflang
hreflang · weight 1 · fix takes hours
Tests: rel=alternate hreflang annotations
Why: x-default names the fallback for unmatched languages.
seo.indexable
Indexability · weight 2 · fix takes hours
Tests: meta robots and X-Robots-Tag
Why: Nothing prevents this page from being indexed.
seo.internallinks
Internal linking · weight 1 · fix takes hours
Tests: Count of internal links
Why: The page participates in the site graph.
seo.keywords
Keyword distribution · weight 0.7 · fix takes hours
Tests: Term frequency in body text
Why: Term frequency looks natural.
seo.lang
Language declaration · weight 0.7 · fix takes minutes
Tests: lang attribute on <html>
Why: The document language is explicit.
seo.og
Open Graph tags · weight 1.1 · fix takes minutes
Tests: og:title, og:description, og:image
Why: Incomplete cards render without an image or summary.
seo.pagination
Pagination links · weight 0 · fix takes hours
Tests: rel=prev / rel=next
Why: Only relevant for paginated series.
seo.robotstxt
robots.txt access · weight 1.5 · fix takes hours
Tests: Disallow rules for /
Why: robots.txt permits crawling this path.
seo.schema
Structured data · weight 1.2 · fix takes hours
Tests: JSON-LD blocks parsed and validated
Why: Valid structured data is machine-readable and rich-result eligible.
seo.title
Title tag · weight 2 · fix takes minutes
Tests: Presence and length of <title>
Why: Google truncates around 580px (~60 characters); the tail is lost.
seo.twitter
Twitter card · weight 0.6 · fix takes minutes
Tests: twitter:* meta tags
Why: The card type is declared.
seo.url
URL hygiene · weight 0.7 · fix takes hours
Tests: Readability of the URL path
Why: The URL is short and readable.
seo.viewport
Mobile viewport · weight 1 · fix takes minutes
Tests: meta viewport declaration
Why: The page declares responsive behaviour.
seo.wordcount
Content volume · weight 1.2 · fix takes hours
Tests: Words in the main content region
Why: There is enough text to establish topical depth.

Local & Regional weight 0.7 · 8 checks

Local signals decide whether a business appears in map packs and "near me" searches, which is where most local commercial intent lands.

If ignored: The business is invisible in local results even when it ranks for its own name.

local.address
Structured address · weight 1.2 · fix takes hours
Tests: PostalAddress in JSON-LD
Why: Without a machine-readable address, location has to be guessed from prose.
local.currency
Currency signals · weight 0 · fix takes hours
Tests: Currency codes and symbols in content
Why: Currency hints at the market being served.
local.hours
Opening hours · weight 0.7 · fix takes hours
Tests: openingHours in schema
Why: Opening hours are among the most requested local facts.
local.meta
Geographic coordinates · weight 0.6 · fix takes hours
Tests: geo.* meta tags and schema geo property
Why: Coordinates disambiguate businesses with common names or shared street names.
local.nap
NAP on the page · weight 1.2 · fix takes hours
Tests: Name, address and phone in visible text
Why: Partial contact details reduce local trust and matching confidence.
local.napconsistency
NAP consistency · weight 0.8 · fix takes hours
Tests: Phone numbers across sampled pages
Why: Inconsistent contact details across pages undermine local ranking confidence.
local.region
Regional targeting · weight 0.5 · fix takes hours
Tests: hreflang region codes
Why: Region-qualified hreflang targets country audiences precisely.
local.schema
LocalBusiness schema · weight 1.6 · fix takes hours
Tests: schema.org business types in JSON-LD
Why: Local business schema is what feeds map packs and knowledge panels.

AI Visibility weight 1.2 · 21 checks

Assistants and answer engines read raw HTML and rarely execute JavaScript. This category decides whether the content can be reached, understood and quoted by each of them individually — a crawler blocked in robots.txt is invisible regardless of how good the content is.

If ignored: The page contributes nothing to AI answers about the topic, and competitors get cited instead.

ai.answerfirst
Question headings · weight 0.7 · fix takes hours
Tests: Headings phrased as questions
Why: Question headings match how people actually query, and give models a clean anchor.
ai.chunkability
Chunkability · weight 1.1 · fix takes hours
Tests: Headings per volume of text
Why: The document splits cleanly into topically coherent chunks.
ai.citable
Citation signals · weight 1 · fix takes hours
Tests: Author, date and source attribution
Why: Undated, unattributed pages are cited less and trusted less.
ai.crawler.applebotextended
Applebot-Extended access · weight 0.5 · fix takes hours · derived
Tests: robots.txt rules for Applebot-Extended on /
Why: Apple uses this agent for Apple Intelligence training. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
ai.crawler.bingbot
Bingbot access · weight 0.9 · fix takes hours · derived
Tests: robots.txt rules for Bingbot on /
Why: Microsoft may fetch this page for Bing index, used by Copilot.
ai.crawler.ccbot
CCBot access · weight 0.4 · fix takes hours · derived
Tests: robots.txt rules for CCBot on /
Why: Common Crawl uses this agent for open corpus many models train on. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
ai.crawler.chatgptuser
ChatGPT-User access · weight 0.8 · fix takes hours · derived
Tests: robots.txt rules for ChatGPT-User on /
Why: OpenAI uses this agent for fetches a page when a user asks about it. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
ai.crawler.claudebot
ClaudeBot access · weight 0.7 · fix takes hours · derived
Tests: robots.txt rules for ClaudeBot on /
Why: Anthropic uses this agent for training corpus. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
ai.crawler.claudesearchbot
Claude-SearchBot access · weight 0.9 · fix takes hours · derived
Tests: robots.txt rules for Claude-SearchBot on /
Why: Anthropic may fetch this page for Claude search results.
ai.crawler.claudeuser
Claude-User access · weight 0.8 · fix takes hours · derived
Tests: robots.txt rules for Claude-User on /
Why: Anthropic may fetch this page for fetches a page when a user asks about it.
ai.crawler.googlebot
Googlebot access · weight 1.2 · fix takes hours · derived
Tests: robots.txt rules for Googlebot on /
Why: Google may fetch this page for web and AI Overviews indexing.
ai.crawler.googleextended
Google-Extended access · weight 0.7 · fix takes hours · derived
Tests: robots.txt rules for Google-Extended on /
Why: Google uses this agent for Gemini grounding and training. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
ai.crawler.gptbot
GPTBot access · weight 0.7 · fix takes hours · derived
Tests: robots.txt rules for GPTBot on /
Why: OpenAI uses this agent for training corpus. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
ai.crawler.oaisearchbot
OAI-SearchBot access · weight 0.9 · fix takes hours · derived
Tests: robots.txt rules for OAI-SearchBot on /
Why: OpenAI uses this agent for ChatGPT search results. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
ai.crawler.perplexitybot
PerplexityBot access · weight 0.9 · fix takes hours · derived
Tests: robots.txt rules for PerplexityBot on /
Why: Perplexity uses this agent for answer citations. Blocking it removes this page from that surface. This is often deliberate — but it should be a decision, not an accident.
ai.crawlers.summary
Crawler access summary · weight 0 · fix takes hours
Tests: All documented AI and search crawlers
Why: A roll-up of the individual crawler signals above.
ai.llmstxt
llms.txt · weight 0.9 · fix takes minutes
Tests: Presence of /llms.txt
Why: An emerging convention for pointing language models at your canonical content.
ai.nojs
Content without JavaScript · weight 2 · fix takes weeks
Tests: Text present in the raw HTML response
Why: The content is fully readable by non-executing crawlers.
ai.qaschema
Question schema · weight 0.9 · fix takes hours
Tests: FAQPage / QAPage / HowTo in JSON-LD
Why: Question schema makes answers directly extractable.
ai.ratio
Content-to-markup ratio · weight 0.8 · fix takes hours
Tests: Visible text bytes over total HTML bytes
Why: A very low ratio means retrieval systems wade through markup to find little content.
ai.semantic
Semantic HTML · weight 1 · fix takes hours
Tests: Use of semantic sectioning elements
Why: The document structure is explicit and machine-readable.

DNS & Email weight 0.9 · 10 checks

DNS decides whether the site resolves at all, and the mail records decide whether anyone can forge email from this domain. Both are invisible from the page itself and are among the most common silent failures.

If ignored: A single nameserver becomes an outage; missing SPF and DMARC let anyone send phishing that appears to come from you.

dns.a
IPv4 address · weight 1.5 · fix takes hours
Tests: A records
Why: The hostname resolves for IPv4 clients.
dns.aaaa
IPv6 address · weight 0.7 · fix takes hours
Tests: AAAA records
Why: IPv6-only clients and some mobile networks reach IPv6 destinations more directly. Adoption is now past half of Google traffic in several countries.
dns.caa
CAA record · weight 0.7 · fix takes minutes
Tests: CAA records
Why: CAA names which certificate authorities may issue for this domain. Without it, any public CA may issue a certificate for you.
dns.dkim
DKIM signing · weight 0 · fix takes hours
Tests: DKIM selector records
Why: DKIM keys live at a selector name chosen by the sender. Probing common selectors would produce false negatives presented as findings, so it is left untested rather than guessed.
dns.dmarc
DMARC policy · weight 1.2 · fix takes minutes
Tests: _dmarc TXT record
Why: DMARC is what actually tells receivers to act on SPF and DKIM failures, and what gives you visibility into abuse of your domain. Without it, SPF alone changes little.
dns.dnssec
DNSSEC · weight 0 · fix takes hours
Tests: DNSSEC validation
Why: Confirming DNSSEC requires a resolver that reports the authenticated-data flag. This host does not expose it, so the answer is unknown rather than negative.
dns.mx
Mail exchangers · weight 0 · fix takes hours
Tests: MX records
Why: This domain does not receive mail. That is normal for a site-only domain, but it means the mail-authentication checks below apply differently.
dns.ns
Nameservers · weight 0 · fix takes hours
Tests: NS records at this name
Why: Nameservers are published at the zone apex and inherited by subdomains. Their absence here is correct delegation, not a fault.
dns.spf
SPF record · weight 1.3 · fix takes minutes
Tests: v=spf1 TXT record
Why: Without SPF, anyone can send mail claiming to be from this domain and receiving servers have no way to reject it. This applies even to domains that never send mail.
dns.txt
TXT records · weight 0 · fix takes hours
Tests: All TXT records at the apex
Why: Verification tokens accumulate; stale ones from decommissioned services are worth removing.

TLS & Certificate weight 1.1 · 10 checks

The certificate is the difference between a working site and a full-page browser warning. Expiry is the single most common cause of sudden, total, self-inflicted downtime on the web.

If ignored: When the certificate lapses the site is effectively offline: every visitor meets an interstitial, and most leave.

tls.available
TLS availability · weight 2.5 · fix takes hours
Tests: TLS handshake on port 443
Why: The server negotiates TLS successfully.
tls.chain
Certificate chain · weight 1 · fix takes minutes
Tests: Intermediate certificates presented
Why: Clients can build a complete path to a trusted root.
tls.cipher
Cipher strength · weight 0.8 · fix takes minutes
Tests: Negotiated cipher suite
Why: The negotiated suite is of current strength.
tls.expiry
Certificate expiry · weight 2.5 · fix takes minutes
Tests: notAfter date
Why: The certificate is comfortably current.
tls.hostname
Hostname match · weight 1.8 · fix takes hours
Tests: Subject alternative names against the requested host
Why: The certificate was issued for this hostname.
tls.issuer
Certificate authority · weight 0 · fix takes hours
Tests: Issuer of the presented certificate
Why: Who vouched for this certificate.
tls.lifetime
Certificate lifetime · weight 0.6 · fix takes minutes
Tests: Validity window of the certificate
Why: Within the limit browsers accept.
tls.protocol
TLS version · weight 1 · fix takes minutes
Tests: Negotiated protocol
Why: TLS 1.3 removes the legacy handshake weaknesses and completes in fewer round trips.
tls.transparency
Certificate transparency · weight 0 · fix takes hours
Tests: Presence in public CT logs
Why: Confirming CT inclusion means asking a third-party log. This engine makes no external calls, so this is out of scope rather than failed.
tls.trusted
Certificate trust · weight 2 · fix takes hours
Tests: Chain verification against the system trust store
Why: Browsers will accept the certificate without an interstitial warning.

Security weight 1.3 · 18 checks

Security controls decide whether traffic can be intercepted, whether injected script can execute, and whether credentials or internal files are exposed to anyone who looks.

If ignored: Ranges from browser warnings that scare users off, to account compromise and disclosure of data you are legally responsible for.

Method note. Findings are inferred from HTTP responses. No certificate chain parsing or vulnerability database is used.
sec.banner
Version disclosure · weight 0.8 · fix takes minutes
Tests: Server and X-Powered-By headers
Why: No exact version is advertised.
sec.blank
target=_blank hygiene · weight 0.7 · fix takes minutes
Tests: rel on links opening a new tab
Why: New-tab links cannot reach back into this page.
sec.cookies
Cookie flags · weight 0 · fix takes hours
Tests: Secure / HttpOnly / SameSite on Set-Cookie
Why: Nothing to evaluate.
sec.cors
CORS policy · weight 1 · fix takes hours
Tests: Access-Control-Allow-Origin
Why: No cross-origin reads are permitted, which is the safe default.
sec.crossorigin
Cross-origin isolation · weight 0.6 · fix takes minutes
Tests: COOP / COEP / CORP headers
Why: These headers isolate your browsing context from cross-origin attacks like Spectre and tab-nabbing.
sec.csp
Content Security Policy · weight 1.6 · fix takes days
Tests: Content-Security-Policy header
Why: CSP is the main defence against cross-site scripting and injected content.
sec.exposed
Exposed paths · weight 1.8 · fix takes hours
Tests: Probe of commonly leaked files
Why: Common sensitive paths are not reachable.
sec.forms
Form safety · weight 0 · fix takes hours
Tests: Form action targets
Why: Nothing to evaluate.
sec.framing
Clickjacking protection · weight 1.1 · fix takes minutes
Tests: X-Frame-Options or CSP frame-ancestors
Why: Framing by third-party sites is restricted.
sec.hsts
HSTS · weight 1.4 · fix takes minutes
Tests: Strict-Transport-Security header
Why: Subdomains remain downgradeable.
sec.https
HTTPS · weight 2.5 · fix takes hours
Tests: Scheme of the final URL
Why: Traffic is encrypted in transit.
sec.inline
Unsafe inline patterns · weight 0.8 · fix takes hours
Tests: Dangerous constructs in inline script and attributes
Why: No obviously injectable inline patterns.
sec.mixed
Mixed content · weight 1.3 · fix takes hours
Tests: http:// subresources on an https:// page
Why: Every subresource loads securely.
sec.permissions-policy
Permissions Policy · weight 0.7 · fix takes minutes
Tests: permissions-policy header
Why: Declares which browser features (camera, geolocation, microphone) the page may use.
sec.redirect
HTTP redirect · weight 1.5 · fix takes minutes
Tests: Behaviour of http:// requests
Why: Visitors arriving over HTTP are upgraded automatically.
sec.referrer-policy
Referrer Policy · weight 0.9 · fix takes minutes
Tests: referrer-policy header
Why: Controls how much of your URL leaks to third parties in the Referer header.
sec.secrets
Secrets in source · weight 1.8 · fix takes hours
Tests: Credential patterns in the served HTML
Why: No recognisable credential patterns in the markup.
sec.x-content-type-options
X Content Type Options · weight 1 · fix takes minutes
Tests: x-content-type-options header
Why: Prevents browsers from second-guessing declared content types (MIME sniffing).

Privacy & Policies weight 0.9 · 7 checks

Consent and policy handling is the difference between lawful data collection and an enforceable violation. GDPR, ePrivacy and CCPA all attach real penalties.

If ignored: Fines assessed on global turnover, plus the reputational cost of being seen to track people without asking.

privacy.consent
Consent before tracking · weight 1.8 · fix takes days
Tests: Tracking scripts versus a consent platform
Why: Nothing on the page triggers a consent obligation.
privacy.cookies
Cookies before consent · weight 1.2 · fix takes days
Tests: Set-Cookie on the first response
Why: Nothing is stored before the visitor has chosen.
privacy.origins
Third-party origins · weight 0.8 · fix takes hours
Tests: Distinct external hosts loading resources
Why: A contained third-party surface.
privacy.privacy
Privacy policy · weight 1.6 · fix takes days
Tests: A linked Privacy policy page
Why: A privacy policy is legally required almost everywhere once you process any personal data.
privacy.readability
Policy readability · weight 0.6 · fix takes hours
Tests: Flesch Reading Ease of the privacy policy
Why: GDPR requires privacy information in clear, plain language. A very difficult score suggests it is not.
privacy.terms
Terms of service · weight 0.9 · fix takes days
Tests: A linked Terms of service page
Why: Terms define the contract between you and your users.
privacy.trackers
Third-party tracking · weight 1 · fix takes hours
Tests: Known analytics and advertising scripts
Why: No third-party tracking means no consent obligation from tracking.

Infrastructure weight 0.9 · 11 checks

Delivery decides how long a visitor waits before anything appears. Latency and caching behaviour feed directly into Core Web Vitals, which are a ranking input.

If ignored: Measurable drop-off: bounce rate climbs with every additional second before first paint.

Method note. Everything here is inferred from HTTP responses. No DNS lookup, WHOIS or certificate parsing is performed.
infra.caching
Caching headers · weight 0.9 · fix takes minutes
Tests: Cache-Control, ETag and Last-Modified
Why: Caching behaviour is explicitly declared.
infra.cdn
Delivery fingerprint · weight 0 · fix takes hours
Tests: Server and CDN headers
Why: Identified from response headers alone.
infra.compression
Compression · weight 1 · fix takes minutes
Tests: Content-Encoding on the HTML response
Why: Compressed HTML transfers in a fraction of the bytes.
infra.ip
Resolved address · weight 0 · fix takes hours
Tests: Peer address of the connection
Why: The address the connection actually terminated on.
infra.protocol
HTTP protocol · weight 0.9 · fix takes hours
Tests: Negotiated protocol version
Why: Multiplexing removes the head-of-line blocking that limits HTTP/1.1.
infra.redirects
Redirect chain · weight 1 · fix takes minutes
Tests: Hops between the requested and final URL
Why: A single redirect is normal and inexpensive.
infra.robots
robots.txt · weight 1 · fix takes hours
Tests: Reachability of /robots.txt
Why: Crawlers read this first; a missing or broken file wastes crawl budget.
infra.sitemap
XML sitemap · weight 1.2 · fix takes hours
Tests: Reachability and parsing of sitemaps
Why: Sitemaps are the most direct way to tell a crawler what exists.
infra.status
Response status · weight 1.5 · fix takes hours
Tests: HTTP status of the final URL
Why: The page is served successfully.
infra.ttfb
Time to first byte · weight 1.1 · fix takes days
Tests: Server response latency
Why: The server responds promptly.
infra.weight
HTML document size · weight 0.8 · fix takes hours
Tests: Bytes of the HTML response
Why: Large HTML delays the parser before any asset is even discovered.

Tech Stack & APIs weight 0.8 · 9 checks

Every third-party script is code you do not control, executing with full access to your page. The stack determines both performance cost and how much trust you have extended to others.

If ignored: A compromised vendor becomes a compromise of your site, and unbounded third-party weight quietly degrades performance.

tech.endpoints
API endpoints · weight 0 · fix takes hours
Tests: URLs referenced by fetch/XHR/GraphQL in inline script
Why: Endpoints inside bundled external files are not visible without executing them.
tech.iframes
Embedded frames · weight 0.6 · fix takes hours
Tests: iframe elements and their sandboxing
Why: No third-party document is embedded in the page.
tech.inlinesize
Inline script volume · weight 0.7 · fix takes hours
Tests: Bytes of inline JavaScript
Why: Inline script cannot be cached separately and inflates every HTML response.
tech.loading
Script loading · weight 1 · fix takes hours
Tests: async / defer on <script src>
Why: Script loading does not block the parser.
tech.scripts
Script inventory · weight 0 · fix takes hours
Tests: Every <script src> on the page
Why: Each third-party script is code you do not control running on your origin.
tech.sri
Subresource Integrity · weight 0.9 · fix takes hours
Tests: integrity attribute on third-party scripts
Why: Without SRI, whoever controls that host controls code running on your page.
tech.stack
Detected stack · weight 0 · fix takes hours
Tests: Markup, asset paths and header fingerprints
Why: Identified from patterns in the served response, not from any external service.
tech.styles
Stylesheet inventory · weight 0 · fix takes hours
Tests: Every external stylesheet
Why: External stylesheets are render-blocking by default.
tech.thirdparty
Third-party weight · weight 1 · fix takes hours
Tests: Count of externally hosted scripts
Why: Each one is a blocking dependency, a privacy exposure and a supply-chain risk.

Content Quality weight 1 · 10 checks

Content quality decides whether someone who arrives actually stays and acts. Readability and structure are what make the difference between skimming and reading.

If ignored: Traffic arrives and leaves without converting, and the weak engagement signal feeds back into lower rankings.

content.boilerplate
Content vs chrome · weight 0.7 · fix takes hours
Tests: Main content share of all page text
Why: The page is mostly content rather than navigation.
content.filler
Filler words · weight 0.7 · fix takes hours
Tests: Intensifiers and hedges per 1000 words
Why: Prose is not padded with intensifiers.
content.freshness
Freshness signals · weight 0.9 · fix takes hours
Tests: Publication and modification dates
Why: Undated content cannot be assessed for currency by readers or ranking systems.
content.media
Media richness · weight 0.7 · fix takes hours
Tests: Images, video, lists and tables per volume of text
Why: The content is visually broken up.
content.paragraphs
Paragraph structure · weight 0.8 · fix takes hours
Tests: Words per paragraph
Why: Paragraphs are a comfortable length.
content.passive
Passive voice · weight 0.8 · fix takes hours
Tests: Share of sentences in passive construction
Why: Heavy passive voice hides who does what and reads as institutional.
content.readability
Readability · weight 1.2 · fix takes days
Tests: Flesch Reading Ease
Why: Dense prose loses general readers and reads as jargon to summarisers.
content.sentences
Sentence variety · weight 1 · fix takes hours
Tests: Sentence length distribution
Why: Long average sentence length is the single biggest driver of unreadability.
content.vocabulary
Vocabulary richness · weight 0.9 · fix takes hours
Tests: Type-token ratio over the first 1200 words
Why: Word choice is varied.
content.volume
Content volume · weight 1.5 · fix takes hours
Tests: Words in the main content region
Why: There is enough writing to evaluate.

AI-Slop Detector weight 0.8 · 8 checks

Search systems increasingly discount unhelpful mass-produced content, and readers recognise it immediately. This is a measure of how generic the writing reads.

If ignored: Content that costs money to produce, ranks poorly, and actively signals low quality to readers.

Method note. A pattern-matching heuristic, not a classifier. Every point is traceable to the evidence listed on each check.
slop.entities
Concrete detail · weight 1.8 · fix takes hours
Tests: Named entities, numbers and quotes per 1000 words
Why: The content is grounded in specifics.
slop.headings
Templated headings · weight 1 · fix takes hours
Tests: Headings matching stock outline patterns
Why: The outline is not stock.
slop.hedging
Hedging and superlatives · weight 1 · fix takes hours
Tests: Density of hedge words and superlatives
Why: Register is measured.
slop.lists
List-heavy structure · weight 0.8 · fix takes hours
Tests: Ratio of list items to paragraphs
Why: Structure is not dominated by bullets.
slop.overall
Slop likelihood · weight 2.5 · fix takes weeks
Tests: Weighted combination of all signals above
Why: The text does not show the characteristic markers of generated filler.
slop.paragraphs
Paragraph uniformity · weight 1 · fix takes hours
Tests: Variation in paragraph length
Why: Generated text often produces paragraphs of almost equal length.
slop.tells
Formulaic phrasing · weight 2 · fix takes hours
Tests: Frequency of known LLM filler phrases
Why: Little to no stock phrasing.
slop.uniformity
Sentence uniformity · weight 1.5 · fix takes hours
Tests: Coefficient of variation of sentence length
Why: Sentence rhythm varies naturally.

Design & UX weight 0.9 · 10 checks

Layout stability and responsive behaviour decide whether the page is usable on a phone, which is where most traffic is and which is what Google indexes.

If ignored: Mobile visitors mis-tap, images jump as they load, and the page is penalised for it.

Method note. Layout is assessed from markup and inline CSS only. No browser rendering is performed, so computed styles are not available.
design.blocking
Render-blocking assets · weight 1 · fix takes days
Tests: Stylesheets and synchronous scripts in <head>
Why: Few assets block the first paint.
design.density
DOM size · weight 0.7 · fix takes hours
Tests: Element count and nesting depth
Why: Large, deeply nested DOMs slow style calculation and layout on every interaction.
design.dimensions
Image dimensions · weight 1.1 · fix takes hours
Tests: width and height attributes
Why: Images without intrinsic dimensions cause layout shift as they load, which is measured by Cumulative Layout Shift.
design.favicon
Icon set · weight 0.9 · fix takes minutes
Tests: Declared favicons and touch icons
Why: The icon set covers tabs, bookmarks and home screens.
design.fontsize
Font size · weight 0.7 · fix takes hours
Tests: Inline font-size declarations under 12px
Why: No obviously undersized inline text.
design.lazy
Lazy loading · weight 0.8 · fix takes minutes
Tests: loading attribute on images
Why: Offscreen images defer without delaying the hero.
design.requests
Subresource count · weight 0.7 · fix takes hours
Tests: Scripts, styles, images and frames referenced
Why: A very high request count multiplies latency, especially on mobile networks.
design.theme
Theme and manifest · weight 0.5 · fix takes minutes
Tests: theme-color meta and web app manifest
Why: These control browser chrome colour and installability.
design.tokens
Design token count · weight 0.6 · fix takes hours
Tests: Distinct colours and font stacks in the markup
Why: The visual vocabulary is contained.
design.viewport
Responsive viewport · weight 1.8 · fix takes minutes
Tests: meta viewport declaration
Why: The page adapts to device width and permits zoom.

Accessibility weight 1 · 16 checks

Accessibility decides whether people using a screen reader, keyboard or magnifier can use the site at all. Most of what fails here also degrades the experience for everyone else — unlabelled controls and broken heading order confuse sighted users too.

If ignored: A share of your audience simply cannot complete the task. In the EU, UK and US this is also enforceable: accessibility lawsuits against websites run into the thousands each year.

Method note. Automated checks find violations; they cannot prove conformance. Only about a third of WCAG criteria are machine-testable, and a clean result here is a starting point for manual testing, not a compliance statement.
a11y.aria
ARIA usage · weight 1 · fix takes hours
Tests: Role validity and reference integrity
Why: Broken ARIA is worse than none: an invalid role or a reference to a missing id silently overrides the element's real semantics. WCAG 4.1.2.
a11y.autoplay
Autoplaying media · weight 0.9 · fix takes minutes
Tests: autoplay on audio and video
Why: Nothing plays audio without consent.
a11y.captions
Video captions · weight 0.8 · fix takes days
Tests: track elements on video
Why: Without captions the content is unavailable to deaf and hard-of-hearing users, and to anyone in a noisy place. WCAG 1.2.2. Note this only detects a declared track — it cannot judge caption quality, and embedded players are not visible to this check.
a11y.contrast
Colour contrast · weight 0 · fix takes days
Tests: Foreground and background colour pairs
Why: Real contrast depends on computed styles from stylesheets, inheritance and layering — which needs a rendering engine. Only inline colour pairs can be read from markup, and none were present. Reporting a pass here would be misleading.
a11y.dupeids
Duplicate IDs · weight 1 · fix takes hours
Tests: Uniqueness of id attributes
Why: Label association, aria-labelledby and aria-describedby all resolve by id and take the first match. Duplicates silently point assistive technology at the wrong element. WCAG 4.1.1.
a11y.headings
Heading structure · weight 1.2 · fix takes hours
Tests: Heading levels and order
Why: A broken outline makes heading navigation unreliable — users skip past content or lose their place in the hierarchy.
a11y.iframetitle
Frame titles · weight 0.8 · fix takes minutes
Tests: title attribute on iframes
Why: An untitled frame is announced only as "frame", giving no clue whether it is a video, a map or an advert. WCAG 4.1.2.
a11y.imgalt
Image alternatives · weight 1.5 · fix takes hours
Tests: alt attribute on images
Why: An image with no alt is announced as "image" or by its filename, which tells a blind user nothing. Decorative images need alt="" so they are skipped. WCAG 1.1.1.
a11y.labels
Form labels · weight 1.5 · fix takes hours
Tests: Accessible name on form controls
Why: Every input announces what it is for.
a11y.landmarks
Landmark regions · weight 1.2 · fix takes hours
Tests: main, nav, header and footer regions
Why: Users of assistive technology can skip directly to the content.
a11y.lang
Document language · weight 1.4 · fix takes minutes
Tests: lang attribute on <html>
Why: Assistive technology can select the right pronunciation rules.
a11y.name
Interactive element names · weight 1.4 · fix takes hours
Tests: Accessible name on links and buttons
Why: Every control announces its purpose.
a11y.skiplink
Skip link · weight 0.7 · fix takes minutes
Tests: A link that bypasses repeated navigation
Why: Keyboard users can jump straight to the content. WCAG 2.4.1.
a11y.tabindex
Tab order · weight 0.8 · fix takes minutes
Tests: Positive tabindex values
Why: Focus follows document order.
a11y.title
Page title · weight 1.2 · fix takes minutes
Tests: Non-empty <title>
Why: The page identifies itself when announced.
a11y.zoom
Pinch zoom · weight 1.3 · fix takes minutes
Tests: viewport scaling restrictions
Why: Users can magnify the page.

Credibility & Honesty weight 0.9 · 8 checks

Attribution, evidence and honest framing decide whether a visitor believes the page. Dark patterns and unverifiable claims are now actively enforced against.

If ignored: Visitors who do not trust the site do not buy from it, and manufactured urgency is a regulatory target.

cred.author
Author attribution · weight 1 · fix takes minutes
Tests: meta author, schema author and visible byline
Why: Unattributed content cannot demonstrate expertise.
cred.citations
Outbound citations · weight 1 · fix takes hours
Tests: Links to external sources
Why: The content points to verifiable sources.
cred.dates
Publication date · weight 0.9 · fix takes minutes
Tests: Machine-readable dates on the page
Why: Undated content gives no way to assess currency.
cred.guarantee
Guarantee backing · weight 0 · fix takes hours
Tests: Refund or guarantee claims versus a policy page
cred.identity
Who is behind this · weight 1.5 · fix takes hours
Tests: Links to about, contact or imprint pages
Why: Partial identity information leaves visitors unsure who they are dealing with.
cred.pressure
Pressure tactics · weight 1.2 · fix takes hours
Tests: Urgency and scarcity language
Why: No manufactured urgency.
cred.seals
Trust seals · weight 0.8 · fix takes hours
Tests: Security or certification badges and their verification links
Why: A seal that cannot be verified is decoration, and knowingly displaying a fake one is actionable.
cred.socialproof
Social proof backing · weight 1 · fix takes hours
Tests: Claims of recognition versus verifiable evidence
Why: Claims are at least partially substantiated.

Title-Content Match weight 0.8 · 7 checks

When the title promises something the body does not deliver, the click happens and the visit fails. That mismatch is measurable and self-correcting downward.

If ignored: High impressions, high bounce, and a steady slide in rankings as the mismatch is learned.

correlation.clickbait
Clickbait markers · weight 0.8 · fix takes hours
Tests: Patterns in the title
Why: The title makes a straightforward claim.
correlation.descbody
Description covered by body · weight 1.2 · fix takes hours
Tests: Token overlap between description and body
Why: A description promising content the page does not contain reads as bait.
correlation.headings
Headings addressed · weight 1 · fix takes hours
Tests: Heading terms present in body text
Why: Sections deliver on their headings.
correlation.slug
URL slug matches title · weight 0 · fix takes hours
Tests: Token overlap between URL path and title
Why: Homepages have no slug to match.
correlation.stuffing
Title keyword repetition · weight 0.7 · fix takes hours
Tests: Repeated terms within the title
Why: Repeating a keyword inside the title is a recognised spam signal.
correlation.titlebody
Title covered by body · weight 1.8 · fix takes hours
Tests: Token overlap between title and body
Why: Part of the title promise is not reflected in the content.
correlation.titleh1
Title matches H1 · weight 1 · fix takes hours
Tests: Token overlap between title and H1
Why: A title and H1 that disagree send conflicting topic signals.

FAQ & Questions weight 0.7 · 7 checks

Question-and-answer structure is the format that both featured snippets and AI answers extract from. Answering directly beneath the question is what makes it extractable.

If ignored: Content that answers the question loses the snippet to a competitor who structured it better.

faq.answered
Answers present · weight 1.2 · fix takes hours
Tests: Text volume immediately after each question heading
Why: A question heading with no answer under it frustrates readers and produces empty retrieval chunks.
faq.answerlength
Answer depth · weight 0.7 · fix takes hours
Tests: Average words per answer
Why: Very short answers rarely satisfy the query or survive as a citation.
faq.headings
Question-form headings · weight 1 · fix takes hours
Tests: Headings phrased as questions
Why: Questions in headings align the page with real queries.
faq.mismatch
Schema matches page · weight 0 · fix takes hours
Tests: Schema questions present in visible text
faq.schema
FAQ schema · weight 1 · fix takes hours
Tests: FAQPage or QAPage JSON-LD
Why: The questions are there; the machine-readable form is missing.
faq.section
FAQ section · weight 0 · fix takes hours
Tests: An identifiable FAQ region
Why: Not every page needs an FAQ section.
faq.titlequestion
Title question answered · weight 0 · fix takes hours
Tests: Title/description phrased as a question

Discoverability weight 1 · 11 checks

Robots rules, sitemaps and internal linking decide which pages are found and how often they are revisited. A page that is never crawled cannot rank regardless of quality.

If ignored: New content takes weeks to appear, and orphaned pages never appear at all.

disc.breadcrumbs
Breadcrumbs · weight 0 · fix takes hours
Tests: BreadcrumbList schema and breadcrumb markup
Why: Most useful on deep hierarchical sites.
disc.broken
Link health · weight 1.2 · fix takes hours
Tests: HTTP status of sampled links
Why: Linking through redirects adds a hop for every visitor and crawler.
disc.canonicals
Canonical consistency · weight 0.9 · fix takes hours
Tests: rel=canonical across sampled pages
Why: Inconsistent canonical coverage lets duplicate variants slip into the index.
disc.coverage
Sitemap coverage · weight 1 · fix takes hours
Tests: Sitemap URLs versus pages linked from this page
Why: Pages you link to but do not declare are crawled later and less often.
disc.depth
Crawl depth · weight 0.8 · fix takes hours
Tests: Directory depth of linked pages
Why: Linked pages sit close to the root.
disc.feeds
Content feeds · weight 0 · fix takes hours
Tests: RSS or Atom feed declarations
Why: Only relevant for sites that publish a stream of content.
disc.files
Discovery files · weight 0 · fix takes hours
Tests: Probe of conventional well-known files
Why: These files are optional but each one answers a question a machine would otherwise guess at.
disc.lastmod
Sitemap freshness · weight 0.8 · fix takes hours
Tests: lastmod values
Why: lastmod is how crawlers decide what to re-fetch first.
disc.robots
robots.txt · weight 1.1 · fix takes minutes
Tests: Presence and parse of /robots.txt
Why: Crawler rules are explicit and parse cleanly.
disc.sitemap
XML sitemap · weight 1.4 · fix takes hours
Tests: Sitemap discovery and parsing
Why: Errors mean some declared URLs never reach the crawler.
disc.sitemapref
Sitemap in robots.txt · weight 0.8 · fix takes minutes
Tests: Sitemap: directive
Why: Crawlers are pointed straight at the sitemap.

Contact & Exposure weight 0.7 · 8 checks

Reachability is a basic legitimacy signal and, in several jurisdictions, a legal requirement. How addresses are published also decides how much spam you receive.

If ignored: Prospective customers with a question simply leave, and exposed addresses are harvested within days.

contact.email
Contact email · weight 1 · fix takes hours
Tests: Any email address on the page
Why: A reachable address is a basic trust signal and a requirement in several jurisdictions.
contact.form
Contact form · weight 0 · fix takes hours
Tests: Forms with contact-shaped fields
Why: A contact form is one way to offer contact without publishing an address.
contact.inventory
Email inventory · weight 0 · fix takes hours
Tests: Addresses found in text, mailto links, JSON-LD and scripts
Why: Every address here is visible to anyone who reads the page source.
contact.page
Contact page · weight 1 · fix takes hours
Tests: A discoverable contact or imprint page
Why: No route to contact the operator was found from this page.
contact.personal
Personal addresses · weight 0.6 · fix takes hours
Tests: Non-role addresses in the markup
Why: Individual addresses attract targeted phishing and are personal data under GDPR.
contact.phone
Phone number · weight 0.7 · fix takes hours
Tests: Phone patterns and tel: links
Why: For commercial sites a phone number materially raises trust.
contact.scraping
Scraper exposure · weight 0.7 · fix takes hours
Tests: Plain-text addresses in the markup
Why: Unobfuscated addresses in page text are harvested by spam crawlers within days.
contact.securitytxt
security.txt · weight 0.6 · fix takes minutes
Tests: A published security contact
Why: security.txt is how researchers report vulnerabilities to you instead of elsewhere.

What is deliberately not checked

Being clear about the edges matters more than appearing comprehensive.

Anything needing a browser

No JavaScript is executed, so client-rendered content is reported as unreachable rather than scored. That is a deliberate choice: it mirrors what crawlers and AI retrieval systems get.

Anything needing a third party

No WHOIS, no CVE database, no PageSpeed field data, no backlink or domain-authority numbers. Every one of those requires a service we do not control, and the whole premise here is that we do not depend on one.

Inferred, and labelled as such

Infrastructure findings — CDN, server software, protocol, caching — are inferred from response headers. Where a finding is an inference rather than a measurement, the report says so on the card itself.

Sites that block us

If a site refuses server-side requests or serves a challenge page, it is scored on what is reachable with the limitation stated. No number is invented to fill the gap.

Prefer to read the output rather than the description? Every audit exposes its full raw result at the API, including the evidence behind each verdict, and /api/v1/llm?url=… returns the whole thing as Markdown.