{"slug": "a-technical-seo-audit-should-end-in-a-decision-not-a-score", "title": "A Technical SEO Audit Should End in a Decision, Not a Score", "summary": "Edikka has introduced an open technical SEO protocol with 44 replayable checks across 13 domains, designed to make audit conclusions falsifiable and release decisions explicit. The protocol rejects simple health scores in favor of six harder questions, separating evidence levels and applying a governance rule that treats 'Not tested' as distinct from 'Compliant'.", "body_md": "A technical SEO audit can report 97% health and still miss the one defect that should stop a release.\n\nAn accidental `noindex`\n\non a key template, an empty application shell, a canonical pointing at a redirect, or a production firewall blocking required resources does not become less serious because 43 other checks are green.\n\nThat is the problem with audit scores: they compress different risks, evidence levels, and unknowns into one reassuring number.\n\nI would rather have an audit that answers six harder questions:\n\nThis article presents the decision model behind an open technical SEO protocol we use at Edikka. It contains 44 replayable checks across 13 domains, but the number is not the point. The point is to make every conclusion falsifiable and every release decision explicit.\n\nIt does **not** predict rankings, traffic, rich results, or AI citations.\n\nEvery applicable check needs two separate classifications:\n\nThen apply a rule that people can challenge:\n\n```\nIF an applicable Blocking check is Non-compliant\n   OR an applicable Blocking check is Not tested\nTHEN NO-GO\n\nELSE IF a Major non-compliance remains\nTHEN ARBITRATION REQUIRED\n\nELSE GO WITH RESERVATIONS\n```\n\nThis is an Edikka governance rule, not an industry standard. A team may choose stricter thresholds. What matters is that the rule is written before the result is known.\n\nThe uncomfortable part is intentional: **Not tested is not the same as Compliant.**\n\nTechnical audits often merge facts observed from outside a site with private states that only the site owner or search engine can reveal.\n\nKeep them separate.\n\n| Evidence level | Examples | What it can establish | What it cannot establish |\n|---|---|---|---|\n| Public | HTTP response, `robots.txt` , source HTML, rendered DOM, sitemap, JSON-LD |\nWhat a documented client observed at a documented time | What Google crawled, selected, or indexed |\n| Search Console | URL Inspection, Google-selected canonical, Pages and Core Web Vitals reports | The state reported for the property and inspected sample | The single cause of a ranking change |\n| Server logs | Verified crawler requests, response codes, frequency, bytes | An interaction received by the infrastructure | How the fetched content was subsequently used |\n| Configuration | CDN, WAF, CMS, deployment and routing rules | The configured intent, once tested | That every edge, cache key, and route behaves identically |\n\nA public audit can establish that a page declares a coherent canonical. It cannot honestly claim that Google selected that canonical without Search Console evidence.\n\nThat boundary improves the audit. It turns “Google has indexed the right page” into two testable statements:\n\n“SEO-friendly” is too vague to debug. A URL passes through distinct stages:\n\n| Stage | Diagnostic question | Useful evidence |\n|---|---|---|\n| Discovery | Does a public path lead to the URL? | HTML links, sitemap, referring URLs in logs |\n| Crawling | May the crawler request it? |\n`robots.txt` , HTTP response, verified logs |\n| Rendering | Does critical content exist after execution? | Source HTML, rendered DOM, URL Inspection |\n| Indexing | Which URL and content did the engine retain? | URL Inspection and indexing reports |\n| Serving | Is the page selected for this query and context? | Search performance and observed results |\n\nA `200`\n\nresponse proves that the server returned a successful representation. It does not prove discovery, indexation, or selection for a query.\n\nA sitemap declares candidate URLs. It is not an indexation certificate.\n\nDo not rely on a `HEAD`\n\nrequest alone. Applications, CDNs, and firewalls can handle `HEAD`\n\nand `GET`\n\ndifferently.\n\nRecord the final status, complete redirect count, effective URL, and duration:\n\n```\nTARGET_URL=\"https://example.com/important-page\"\n\ncurl --location --silent --show-error --output /dev/null \\\n  --write-out 'status=%{http_code}\\nredirects=%{num_redirects}\\nfinal=%{url_effective}\\ntime=%{time_total}s\\n' \\\n  \"$TARGET_URL\"\n```\n\nReplay more than the happy path:\n\nThe expected result is not “everything returns 200.” The expected result is that each case returns the status and destination intended for that resource.\n\nMany technical SEO failures begin with the right intent and the wrong mechanism.\n\n| Intent | Primary mechanism | Evidence to retain | Dangerous shortcut |\n|---|---|---|---|\n| Reduce crawling |\n`robots.txt` for compliant crawlers |\nParsed rule plus logs | Treating it as access control |\n| Remove a page from an index | Accessible `noindex` directive |\nSource/header plus URL Inspection after recrawl | Blocking the page before the crawler can read `noindex`\n|\n| Consolidate duplicates | Redirect or `rel=\"canonical\"` , depending on the case |\nConverging signals plus selected canonical | Canonicalising genuinely different pages |\n| Protect private data | Server-side authentication and authorisation | Anonymous request denied with no sensitive body | Publishing the data and hiding it from robots |\n\n[Google's robots directives documentation](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag) explicitly notes that crawlers must be allowed to access a page to read its `noindex`\n\nrule. The [Robots Exclusion Protocol](https://www.rfc-editor.org/rfc/rfc9309) also defines crawling rules, not a security boundary.\n\nAvoid arguments such as “React is bad for SEO” or “SSR solves SEO.” Framework labels are not evidence.\n\nFor every priority template, compare at least:\n\nThis small Playwright probe records a few invariants from the rendered page:\n\n``` js\nimport { chromium } from \"playwright\";\n\nconst url = process.argv[2];\nif (!url) throw new Error(\"Usage: node inspect-page.mjs <url>\");\n\nconst browser = await chromium.launch();\nconst page = await browser.newPage();\nconst response = await page.goto(url, { waitUntil: \"networkidle\" });\n\nconst evidence = await page.evaluate(() => ({\n  title: document.title,\n  h1: [...document.querySelectorAll(\"h1\")].map((node) =>\n    node.textContent?.trim(),\n  ),\n  canonical:\n    document.querySelector('link[rel=\"canonical\"]')?.getAttribute(\"href\") ?? null,\n  robots:\n    document.querySelector('meta[name=\"robots\"]')?.getAttribute(\"content\") ?? null,\n  crawlableLinks: document.querySelectorAll(\"a[href]\").length,\n  jsonLdBlocks: document.querySelectorAll(\n    'script[type=\"application/ld+json\"]',\n  ).length,\n  mainTextCharacters:\n    document.querySelector(\"main\")?.textContent?.trim().length ?? 0,\n}));\n\nconsole.log(JSON.stringify({\n  requestedUrl: url,\n  finalUrl: page.url(),\n  status: response?.status() ?? null,\n  ...evidence,\n}, null, 2));\n\nawait browser.close();\n```\n\nThis does not reproduce Googlebot or prove indexation. It provides replayable browser evidence that can be compared with the raw response and Search Console.\n\nThe complete protocol is larger, but these seven checks expose why severity matters more than a percentage:\n\n| Gate | Evidence expected | Typical severity |\n|---|---|---|\n| Final public URL returns the intended response after a controlled redirect chain | URL, timestamp, final status, effective URL | Blocking |\nRequired resources are crawlable and no accidental `noindex` exists |\n`robots.txt` , headers, source HTML |\nBlocking |\n| Critical content exists in source HTML or observable rendered output | Raw response, rendered DOM, inspection | Blocking |\n| Canonical signals converge | Final URL, canonical, sitemap, internal links | Major |\n| Important pages receive crawlable HTML links | Source URL, destination, anchor, status | Major |\n| JSON-LD describes visible entities without invented claims | Parsed graph plus visible-content comparison | Major |\n| Field Core Web Vitals are read separately from laboratory scores | LCP, INP, CLS at the 75th percentile by device/group | Major |\n\nNotice the last row: a Lighthouse score is diagnostic laboratory evidence. It is not field evidence, and a score of 100 does not guarantee good real-user Core Web Vitals.\n\nIf a conclusion cannot be exported, compared, and replayed, it will be difficult to govern after the next deployment.\n\nA minimal result might look like this:\n\n```\n{\n  \"id\": \"TS25\",\n  \"url\": \"https://example.com/product/42\",\n  \"observed_at\": \"2026-08-25T13:00:00Z\",\n  \"status\": \"Non-compliant\",\n  \"severity\": \"Blocking\",\n  \"access\": \"Public\",\n  \"evidence\": {\n    \"raw_html\": \"main content absent\",\n    \"rendered_dom\": \"main content present after API response\"\n  },\n  \"limitation\": \"Local Chromium is not Google URL Inspection\",\n  \"owner\": \"Frontend platform\",\n  \"decision\": \"NO-GO\"\n}\n```\n\nThe `limitation`\n\nfield is as important as the observation. It prevents a local browser result from silently becoming a claim about Google.\n\nNot every audit check belongs in CI. The stable ones often do:\n\n`noindex`\n\nchanges;Use representative fixture URLs for each important template. Preserve the timestamped report as a build artifact. Link it to the deployment. Replay it after release.\n\nAutomation detects a defined regression. It does not own the business exception or the final release decision. Every exception still needs an owner, a reason, and an expiry date.\n\nThe full method currently contains **44 checks across 13 domains**: HTTP, robots, indexation, canonicalisation, sitemaps, internal discoverability, URL spaces, internationalisation, JavaScript, semantic HTML, structured data, performance, edge behaviour, CI, and crawler policies.\n\nThe assets are open under CC BY 4.0:\n\nPrimary references used by the protocol include [RFC 9110 for HTTP semantics](https://www.rfc-editor.org/rfc/rfc9110), [RFC 9309 for the Robots Exclusion Protocol](https://www.rfc-editor.org/rfc/rfc9309), [Google's canonicalisation guidance](https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls), [JavaScript SEO documentation](https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics), and [the Core Web Vitals threshold methodology](https://web.dev/articles/defining-core-web-vitals-thresholds).\n\nThe question I would ask before your next deployment is not:\n\nWhat technical SEO score did we get?\n\nIt is:\n\nWhich applicable failure would stop this release, and do we have the evidence to detect it?\n\nWhat is the technical SEO invariant that should be a NO-GO in your stack?\n\n*AI-assistance disclosure: this DEV edition was adapted from my original Edikka protocol with AI assistance for structure and English editing. The audit model, controls, evidence boundaries, examples, verification, and publication decision remain my responsibility.*", "url": "https://wpnews.pro/news/a-technical-seo-audit-should-end-in-a-decision-not-a-score", "canonical_source": "https://dev.to/edikka/a-technical-seo-audit-should-end-in-a-decision-not-a-score-b6i", "published_at": "2026-08-24 05:52:53+00:00", "updated_at": "2026-08-24 06:13:16.467127+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Edikka"], "alternates": {"html": "https://wpnews.pro/news/a-technical-seo-audit-should-end-in-a-decision-not-a-score", "markdown": "https://wpnews.pro/news/a-technical-seo-audit-should-end-in-a-decision-not-a-score.md", "text": "https://wpnews.pro/news/a-technical-seo-audit-should-end-in-a-decision-not-a-score.txt", "jsonld": "https://wpnews.pro/news/a-technical-seo-audit-should-end-in-a-decision-not-a-score.jsonld"}}