Skip to main content
Back to Blogstrategy

Three Things Your SEO Checker Cannot See (And the Tool We Built for One of Them)

RedClaw Performance Team
RedClaw Performance Team
Date
Reading time
11 min read

TL;DR: we pointed one content-acceptance script at 24 of our own sites on the same day. The reports were not the valuable part. The valuable part was watching the script fail in three specific ways: ways that are structural rather than bugs, and that almost certainly apply to whatever checker you are running. One: a configuration mistake produces a site-wide failure that looks exactly like a content catastrophe. Three sites opened at 0/42, 0/61 and 0/78. Two: counting how many distinct domains an article cites tells you nothing about whether those domains still resolve — one site had 92 articles citing three sources that were all broken, with the gate green. Three: an entire category of defect exists only in the HTML your server actually sends, so a checker reading your source files cannot see it by definition. We open-sourced the third one.

The setup

We run a portfolio of our own sites plus client work. On 8 September 2026 we ran the same acceptance script across 24 of them in one day: same thresholds, same gate definitions, same human judgement call at the end.

Single-site reports we do every week, and they had not surfaced any of this. The cross-section did, and the reason is worth stating. A false negative is invisible in a single report. Nobody investigates a green light. You only notice that a check never fires when you watch it not fire across two dozen structurally different codebases in an afternoon.

Blind spot one: configuration that fakes a content catastrophe

Three sites came back completely red on the first run:

SiteFirst runActual cause
A (Markdown)0 pass / 42 failNo config file. The script looked for description and date; that site's frontmatter uses different names
B (Markdown)0 pass / 61 failTwo config values, both wrong. Below
C (Markdown)0 pass / 78 failSame shape: field mapping mismatch

Site B is the instructive one, because its config file existed and looked perfectly reasonable.

Value one: trailing slashes. That site's canonicals have no trailing slash. The config never declared it, and the script defaults to expecting one. Result: 60 of 60 files reported "internal links missing trailing slash." Had we followed the tool, we would have hand-built 60 redirects on a site that did not need any.

Value two: a leading slash in moneyPaths. The config said ["/tools/", "/try"]. The script joins those values into a regex, producing ^/(/tools/|/try…), which can never match, so 61 of 61 files reported "no link to a money page." With the slashes removed, the number of articles genuinely missing a money-page link was five.

The rule that falls out of this:

When a single gate fires on more than 80% of files, assume configuration before you assume content.

Content defects are scattered. Fifty articles written by different people in different months fail in different ways: one is missing sources, one is too short, one has no internal links. They do not line up neatly on one rule. A 60/60 or a 61/61 is the shape of a setting, not the shape of writing.

But "check first" is not "it is always config"

A fourth site made this precise. It opened at 44/44 on one gate: zero external source domains. Same shape, same >80% signal.

It was real. All 44 tutorials on that site had literally no outbound link. grep https?:// returned nothing.

So the usable version has two steps, and the second one matters as much as the first:

  1. One gate over 80%? Go look at the config. Do not edit articles yet.
  2. Config confirmed correct? Then that 80% is a site-level process gap, and you fix the process once rather than 44 articles individually.

We wrote step one into the script: any batch run where a single gate exceeds 80% now prints a line saying it looks like a configuration problem. It does not decide for you. It just makes sure you do not miss the signal.

Blind spot two: counting domains, not checking whether they are alive

Most content checkers, ours included, verify external sourcing by counting distinct domains. Fewer than three, gate. The assumption is that citing several different domains means research happened.

One site broke that assumption completely. Its gates were green. Then we opened the links:

Cited sourceActual stateArticles affected
A meteorological agency's data page40480
A classical-texts database entry200, but a blank page88
An official dictionary's entry IDs200, but all seven IDs point at unrelated words22

92 articles, three source sets, all broken, gate green.

The principle underneath is worth more than the numbers:

Citing a 404 is worse than citing nothing.

Citing nothing is an absence of evidence. Citing a dead link is claiming evidence and then failing to produce it. Nobody will ever tell you: readers do not file bug reports about your citations, they just leave.

The fix is to stop treating "has a link" as binary:

ClassHTTPMeaningGate?
alive2xx / 3xxResolvesNo
blocked401, 403, 405, 429, 451, 503Bot-walled, not deadNo, but flag for a human
dead404, 410, DNS failure, timeoutActually goneYes

The blocked class has to exist separately or you will delete good sources. Real examples from that day: a gambling data site answering 451 to automated requests, a data API answering 503, and a major social platform's domain answering 400 to a spoofed Chrome user-agent while plain curl sailed through.

And a fourth one we hit while verifying this article: Google's own Search Console help page came back dead. curl said 200, the checker said 404. The checker sends HEAD first to save bandwidth, and support.google.com answers HEAD with 404 and GET with 200. Our retry-on-GET path only fired for 405/501/403, so a 404 from HEAD was treated as authoritative.

So: a 404 from HEAD is not an authoritative answer. Retry with GET before you call anything dead. The extra request only happens for URLs that already look dead, and the alternative is a false positive holding back an article that cites real official documentation. False positives that block real content are more expensive than false negatives that let weak content through, because you will act on the false positive and change something that was not broken.

And the honest limit, which any tool making this claim owes you: this verifies reachability, not correctness. Of the three broken source sets above, only the 404 was machine-detectable. The blank page and the mismatched dictionary entries both returned 200. A human reading them is the only thing that catches those.

Blind spot three: defects that only exist after rendering

The third blind spot is structural and unfixable in place, because a checker that reads your source files is reading something where these defects do not yet exist. They are created between the build and the response.

Four real ones from that day:

Replacement characters above the fold. One site had 20 U+FFFD characters across 11 articles' opening screens, produced by a mask/restore step in the build that masked and never restored. They landed on the anchor text of the citations, the exact place a page most needs to look trustworthy. The markdown was clean.

An internal QA block rendered as page copy. One page publicly displayed the string Word count within target band (1800-2200).

JSON-LD↗ disagreeing with the canonical. One site had 12 breadcrumb item URLs without the trailing slash its canonicals carried. To Google that is two URLs for one page↗.

A site-wide soft 404. One host's catch-all rewrite answered every non-existent path with 200.

That last one is the worst, and not for the reason people usually give. Duplicate shells in the index are bad. Worse is this: on a site where nothing 404s, no crawler will ever report a broken internal link, because there are none. Everything resolves. That site had 20 typo'd internal links sitting in plain sight. Buy the most expensive crawler on the market and it will report perfect internal link health.

You can check this in thirty seconds:

curl -s -o /dev/null -w "%{http_code}\n" https://your-domain.example/definitely-not-a-real-path-12345/

404 or 410 is correct. If it returns 200, fix that before you look at any other internal-link number, because none of them mean anything until you do. Google's HTTP status codes documentation↗ and the Search Console Page Indexing report↗ both treat soft 404 as a distinct problem — but they tell you afterwards.

We open-sourced the third one

The rendered-layer checks are generic. They have nothing to do with your content strategy, your vertical, or your quality bar. They are hygiene. So we pulled them out under MIT:

rendered-seo-check↗: single file, zero dependencies, Node 20+.

# Read URLs from the sitemap
npx rendered-seo-check https://example.com

# Or specific pages
npx rendered-seo-check https://example.com/a/ https://example.com/b/

# Your own leak patterns, machine-readable output
npx rendered-seo-check https://example.com --leak='internal-only' --json

It exits 1 on any page-level failure or a failed site-level soft-404 probe, so it goes straight into CI. It also warns on a missing canonical, a badly sized meta description (the one actually served, not the one in your frontmatter), unparseable JSON-LD, and pages that are noindex.

The README is more specific about what it does not do than about what it does: it never judges content, never verifies that a source says what you claimed, does not crawl, and does not execute JavaScript. None of those are things a tool of this shape can do, and not saying so is how you sell someone a guarantee they did not buy.

We did not open-source the content-quality checker. Not because it is clever, but because every threshold in it is a number we reached by being wrong first, repeatedly, on our own sites. Shipping the code without that calibration hands you something that looks like ours and scores differently, which is worse for you than not having it. Rendering hygiene is a commodity. Calibration is not. That is where the line is, and this piece would be worth less if it did not say so.

The three layers, in order

LayerReadsCatchesWhen to run
1. SourceMarkdown / MDX / component propsLength, summary, headings, internal links, source countEvery edit; fine in pre-commit
2. Source livenessThe actual response from every outbound linkDead links, blocked links needing a humanBefore publish, plus a quarterly full sweep
3. RenderedThe HTML your server actually sendsMojibake, leaked internals, JSON-LD mismatch, soft 404After deploy — it does not exist before

The order matters because each layer makes the next one's output trustworthy. Layer three has to run post-deploy, which is precisely why most teams never run it: their CI finishes before the thing being checked exists.

And layer one only means anything once you have confirmed the configuration. Otherwise you get 0/61 and go rewrite sixty articles that were fine.

Verify the tool before you trust the tool.

The same cross-section produced a longer piece on what happens when the content is good and the site still has no traffic, and the vertical-specific version of these checks lives in our complete iGaming SEO guide and the compliance pitfalls piece.

If you would rather have someone run all three layers on your site every week and hand you the numbers, that is our SEO site build and management service.

FAQ

My checker says every article fails. Is my content really that bad?

Probably not. Check the hit rate first: if one gate is firing on more than 80% of files, look at your configuration before you edit anything. The two we hit most often were trailing-slash convention and money-page paths written with a leading slash so the regex never matched.

Is "over 80% means configuration" a reliable rule?

It is a heuristic, not a law, and we have a counter-example: one site's 44/44 was genuine — no outbound links anywhere in 44 tutorials. Treat it as "check config first", never as "ignore it." Once config is confirmed, that 80% is a real site-level gap.

A source returns 403. Is it dead?

No. Split outcomes into alive / blocked / dead. 401, 403, 405, 429, 451 and 503 mean a bot wall, and treating them as dead deletes good sources. Also retry with GET before declaring a 404 dead — some servers, including Google's own help pages, answer HEAD with 404 and GET with 200.

Can a script verify that my citations are accurate?

No, and be suspicious of anything claiming otherwise. A script verifies status codes. A blank page and a page about the wrong topic both return 200. Two of the three broken source sets we found were exactly that.

Why is a site-wide soft 404 so serious?

Because it disables every internal-link check you own. If non-existent paths return 200, no crawler can find a broken link, so typos survive for years. Fix it before you read any internal-link report.

How is this different from Screaming Frog or a normal crawler?

Different job. Crawlers do discovery at scale: find every page, follow every link. This does four specific rendered-layer checks, in one dependency-free file that drops into CI, reading URLs from your sitemap rather than crawling. Use a crawler to find pages; use this to check them.


Explore our advertising strategy & media buying services →

Maximize Your Ad Budget ROI

From account setup to full-funnel tracking, we handle it all.

  • Dedicated account manager with real-time optimization
  • Full tracking infrastructure — every dollar accounted for
  • Cross-platform expertise: Meta, Google, TikTok

Get a free ad account health check

Our specialists review your ad account and point out where budget is being wasted.

100% freeReply within 48 hoursNo contract

Subscribe to Our Newsletter

Weekly insights on ad strategies, industry trends, and practical tips. No fluff.

We never share your email. Unsubscribe anytime.