Soft 404: the missing page that answers 200 OK
Why a not-found page that returns 200 fills the index with garbage, blinds your monitoring, and how to make the server tell the truth about missing addresses.
SEO · Published: 27 September 2026 · 6 min read · Марк Лебедев
A 404 is not a failure. It is the server answering an honest question honestly: there is nothing at this address. A soft 404 is the same answer with the wrong status code — the page says "not found", the HTTP response says 200 OK. Humans read the page; crawlers, monitors and caches read the status. Everyone except the human gets lied to.
Where they come from
Almost nobody writes a soft 404 on purpose. They fall out of reasonable-looking defaults:
- SPA fallback. The classic nginx config for a single-page app is
try_files $uri /index.html;. Every address that is not a file gets the app shell with 200, and the router renders "Page not found" in JavaScript after the status has already been sent. - Empty listings. CMS search, tag and category pages with zero results still render a full template — header, filters, "nothing found" — with 200. Each combination of parameters becomes a separate indexable page.
- Redirect everything home. A catch-all rule that sends every unknown URL to
/with a 301 or 302. Search engines treat a redirect to an unrelated page as a soft 404, and users lose the address they were trying to reach. - Out-of-stock products. The product is gone, the template stays: no price, no description, no photos, one line of "currently unavailable", and a 200.
- WAF and bot challenges. A firewall or CDN challenge page served with 200 instead of 403 or 429. To a crawler, your entire catalogue becomes copies of one "checking your browser" page.
Why it hurts
Garbage in the index. Typos, old campaign URLs and scanner probes all become "pages". Google eventually spots many of them and lists them in the Search Console Soft 404 report — but only after crawling them, and not all of them.
Crawl budget. Every fake page is a fetch the crawler did not spend on real content. On a large site with parameterised listings this is not a rounding error.
Duplicates of the home page. Blanket redirects and SPA shells make thousands of URLs resolve to the same content, which muddies canonical selection for the page you actually care about.
Blind monitoring. Uptime checks, link checkers and synthetic tests look at the status code. If dead links answer 200, every broken-link audit reports a clean site.
Polluted analytics. Hits on nonexistent pages are counted as normal page views, with normal bounce and time-on-page. The "not found" traffic never shows up as an error.
How to test
Request an address that cannot exist and look only at the status:
curl -s -o /dev/null -w "%{http_code}\n" https://example.com/this-page-does-not-exist-8f3a/
Anything other than 404 or 410 is a problem. Repeat for each template that has its own routing: /blog/nonexistent, /product/nonexistent, /search?q=zzzzqx, a missing locale prefix. A SiteScan report does this for you: it checks what the server answers for an address that does not exist and flags a 200.
The fixes
Return a real 404. For a static or prerendered site, let nginx serve a prebuilt page with the right status:
error_page 404 /404.html;
location / {
try_files $uri $uri/ =404;
}
For an SPA with server rendering, the server has to know the route table: if no route matches, or the route matches but the record does not exist, respond with 404 before streaming the HTML. If the server truly cannot know — a pure client-side app behind a dumb host — add <meta name="robots" content="noindex"> to the client-rendered not-found view. That is a last resort: it keeps the page out of the index, but monitors and link checkers still see 200.
Use 410 for content removed for good. A discontinued product or a deleted article is "gone", not "not found". 410 tells crawlers to stop asking sooner.
Redirect only to a genuine equivalent. A 301 is correct when the content moved — the renamed article, the replacement model. A blanket redirect to the home page is not a fix; it is a soft 404 with an extra hop.
Make the 404 page useful, not successful. Search, links to the main sections, for us the scan input — all of it fits on an error page. The page can be as helpful as you like; the status code still has to be 404.
Check-list
- A random URL on every routing template returns 404.
- Empty search and listing pages are noindex or 404.
- Removed content returns 410 or a 301 to a real equivalent.
- No catch-all redirect to the home page.
- Bot challenges return 403 or 429, not 200.
- The 404 page helps the visitor and still answers 404.
Read next
Check how much of this is on your own site
A free scan surfaces broken links, JS errors and performance problems in about a minute.