Soft 404s: When a Missing Page Returns 200
A soft 404 is a missing or empty page that returns HTTP 200 instead of 404. Google won't index it and keeps wasting crawl budget on it. Return a real 404 or 410.
A soft 404 is a page that returns HTTP 200 while its content is empty, missing, or an error message. The status code says "everything is fine" but the body says "page not found." Google detects the mismatch, refuses to index the page, and keeps recrawling it — because a 200 invites return visits. The fix is to make the status code tell the truth: return a real 404 or 410.
What a soft 404 actually is
Google's documentation names the soft 404 as a distinct failure mode: a 2xx response carrying empty or error-like content. The defining feature is the contradiction between the HTTP layer and the content layer. The server hands back 200 OK, so the crawl pipeline treats the URL as a live, valid resource, but when Google inspects the rendered content it finds "no results," "page not found," an empty template, or a near-empty body. Google resolves the conflict against you: it decides the page has no real content and treats it as a 404 regardless of what the header claimed.
Common sources:
- Out-of-stock or discontinued product pages served as 200 with an empty shell.
- Internal search or category pages that return "no results found" but still respond 200.
- Deleted articles that render a friendly "this page no longer exists" message at a 200 status.
- The classic anti-pattern: redirecting every missing URL to the homepage, which Google usually reclassifies as a soft 404 because the homepage does not satisfy the request.
Why Google wastes crawl budget on soft 404s
Because the status code lies, Google cannot use it to prune dead URLs. A correct 404 or 410 tells Google to stop crawling the URL and remove it from the index; a soft 404 does the opposite. The 200 signals a healthy page, so Googlebot keeps returning to it, and the URL lands in limbo — reported as "Soft 404" or "Crawled – currently not indexed" in Search Console.
The cost is twofold. First, crawl waste. On any site large enough for crawl budget to matter, a cluster of soft 404s drains fetch quota that should be spent discovering and refreshing pages you actually want indexed. This is the mechanism our crawl budget guide covers in depth: perceived inventory inflates with thin, error-like URLs, and crawl demand gets spent rediscovering them. Second, quality signals. A site that serves many thin, error-like 200s looks lower quality in aggregate, and that is a site-level drag, not merely a per-URL one.
Crawl rate itself is not a ranking signal, so the harm is not a smaller crawl number — it is that the crawl is spent on the wrong URLs and that dead pages never leave the index cleanly.
How to return a real 404 or 410
Diagnose the URL's true state, then serve the matching status.
- Genuinely gone. Return
404 Not Found, or410 Goneif the removal is permanent. Google treats 404 and 410 as the same removal, though 410 may drop the URL slightly faster. Do not render a friendly "not found" page at a 200 status — the friendly page is fine, but it must ship with a 404 or 410 header. - Moved. Return a
301redirect to the specific replacement URL. Do not funnel everything to the homepage; a mismatched redirect target becomes a soft 404. - Temporarily unavailable. Return
503, optionally with aRetry-Afterheader, so Google knows to come back rather than treating the emptiness as permanent.
A minimal server example:
app.get('/product/:id', async (req, res) => {
const product = await lookup(req.params.id);
if (!product) return res.status(404).render('not-found'); // real 404
res.render('product', { product });
});
Thin and empty-results pages
Not every empty page is a mistake. An empty category or a search page with no matches can be a legitimate live state. The rule is: if you want the page to stay live, either give it real content or add noindex so Google does not judge the emptiness as an error. What you must not do is serve a thin, error-worded page at 200 and leave Google to guess — that is exactly what triggers the soft 404 classification. Persistently thin pages are worth reviewing on their own; Crawlinx flags them as content.thin.
JavaScript apps that render "not found" with a 200
Single-page applications are the modern factory for soft 404s. A client-side router matches an unknown path, renders a "page not found" component, and never changes the HTTP status — the server already returned 200 for the app shell. Google indexes the rendered DOM, sees "not found" content on a 200 URL, and classifies it as a soft 404.
Two reliable fixes for SPAs:
- Redirect missing content to a URL that returns a real 404 at the server level, so the status code is honest.
- Inject
noindexinto the head when the app determines content is missing, so Google keeps the URL out of the index deliberately rather than judging it an error.
Both approaches, and the broader constraint that Google indexes rendered output rather than raw HTML, are covered in our JavaScript SEO and rendering guide. Because the renderer must fetch your assets to reach the "not found" state in the first place, make sure your robots.txt does not block the scripts that decide it.
How Crawlinx detects soft 404s
Crawlinx requires two conditions together before flagging: thin content and an error marker ("not found," "404," "no results," "page doesn't exist") in the title, H1, or first heading. A rich article that merely mentions "404" in its body — an HTTP tutorial, for example — is not flagged, because the marker must appear in the title or H1 and the page must also be thin. Pages already carrying noindex are never flagged, since the owner is clearly handling the state on purpose. The rule is status.soft_404; related signals are status.4xx, content.thin, and index.noindex.
Takeaway
A soft 404 is a lie the server tells: 200 on the outside, "not found" on the inside. Google catches the lie, refuses to index the page, and keeps crawling it. Return a genuine 404 or 410 for gone pages, a targeted 301 for moved ones, and noindex for intentionally empty states. In an SPA, make the server status honest — the client-side router alone cannot.
Audit your own site — free
77 checks, internal PageRank, render-diff. No signup, results in ~30s.