When a page doesn’t exist, the server should answer with HTTP status 404 Not Found (or 410 Gone if it was removed on purpose). A soft 404 is when the server answers 200 OK instead, the status that means “here is a real page”, while the content says the page isn’t there, or there is barely any content at all.

People see an error page either way. Search engines see a successful page, and have to guess.

Why Google cares about soft 404s

  • Ghost pages can get indexed. If every mistyped or deleted URL answers 200, there is an endless supply of “pages” that are all copies of your error page or your homepage.
  • Crawl budget goes on nothing. Google keeps re-fetching URLs it thinks are real instead of dropping them.
  • Search Console reports them. Google labels these URLs “Soft 404” in the Page indexing report and won’t index them, but only after spending crawls working that out.

Google also flags as soft 404s some real pages that look empty: an out-of-stock product with no other content, an empty category, a search results page with no results. Those need content or a real status, not just a server fix.

The usual causes

A catch-all route that renders something for every URL

Single-page apps are the classic case. The server sends the same HTML shell for every path and the JavaScript router decides what to show, so /pricing, /dashboard and /no-such-page all answer 200. The app shows a “not found” view, or quietly redirects to the homepage, but the status code has already been sent.

This happened to our own site. Every URL returned the app shell with a 200, so /privacy, /blog and even /favicon.ico “existed”. The fix was to make the server aware of which routes are real.

A custom 404 page served with the wrong status

Some CMS themes and frameworks render the “page not found” template correctly but forget to set the status, or the hosting layer rewrites the error into a normal page.

Redirecting every missing URL to the homepage

It feels tidy, but Google treats a redirect from a missing page to an unrelated page as a soft 404 too. Visitors who followed a link to something specific land somewhere generic with no explanation.

How to check your site

Ask for a URL that can’t exist and look at the status code:

curl -s -o /dev/null -w '%{http_code}\n' https://example.com/this-page-does-not-exist-8f3a2c

Anything other than 404 or 410 means missing pages aren’t reported as missing. That is exactly how SEO Audit Hub tests for it: during an audit it requests a URL with a random suffix, and flags the site if that answers 200.

How to fix soft 404s

Return a real 404 or 410

Keep the friendly error page, but send it with status 404. Most frameworks have a single place for this; in PHP, for example, http_response_code(404) before rendering the template. Use 410 for content you removed deliberately and won’t bring back.

For single-page apps, teach the server the routes

Google’s JavaScript SEO guidance offers two fixes when the server can’t tell what exists: redirect to a URL that does return a 404, or add <meta name="robots" content="noindex"> to the not-found view. The cleaner fix is on the server: have it check the path against the app’s list of routes before sending the shell, and send the shell with a 404 status when nothing matches. The app can still render its own not-found screen.

Redirect only to a real replacement

If a page moved, a 301 to its new URL is right. If it is gone with no equivalent, let it return 404 or 410 rather than redirecting to the homepage.

Give thin pages a reason to exist, or a real status

For empty categories and out-of-stock products, either add useful content (related items, an expected restock date, alternatives), or, if the page has no future, return 404 or 410, or noindex it.

After deploying a fix, re-run the curl check above. Then, in Google Search Console’s Page indexing report, open the “Soft 404” issue and choose Validate fix, so Google re-checks the affected URLs.