Every web page comes back with a status code before any content. 200 means "here is the page", 404 means "there's nothing here", 410 means "there was something here and it's gone for good". A soft 404 is a page whose content says one thing ("Sorry, this page doesn't exist") while its status code says another (200 OK).
People see an error page either way. Search engines see a working page with very little on it, and have to guess. Google's documentation calls these soft 404s, reports them in Search Console, and recommends returning a real 404 or 410 instead.
Why soft 404s are worth fixing
- Error pages can end up in search results. A crawler that gets
200has no protocol-level reason to drop the URL. Google usually works it out from the content, but that's a guess you don't need it to make. - Crawling time goes to pages that don't exist. On a large site, every soft 404 that gets recrawled is a request not spent on a page you want indexed.
- They hide real problems. A broken link to a page that answers
404shows up in every crawler and log. The same broken link to a soft 404 looks like a working page. - They make your reports wrong. Monitoring, analytics and audits all trust the status code. A site that never returns 404 looks perfectly healthy while visitors hit dead ends.
What causes them
Most soft 404s come from a handful of setups:
- The server sends the error page with the wrong status. A custom "not found" page is configured, but the server returns it with
200. In nginx,error_page 404 =200 /404.html;does exactly that; the=200overrides the status. - Missing URLs redirect to the homepage. Some sites send every unknown address to the homepage with a
301or302. Google's documentation says that redirecting a missing page to an irrelevant one, such as the homepage, may be treated as a soft 404, and visitors land somewhere that isn't what they asked for. - JavaScript apps render "not found" in the browser. In a single-page app, the server returns the same HTML shell with
200for every URL, and the app shows a "not found" screen only after its code runs. The status code never changes. - Catch-all routes in a CMS or framework. A route like
/blog/[slug]renders an empty template, or a search page, for slugs that don't exist, instead of returning 404. - Pages that exist but say almost nothing. Empty category pages, internal search results with no results, or discontinued products reduced to a title. Google may treat very thin pages like these as soft 404s too, even when they aren't errors.
How to find soft 404s
Request a page that can't exist
The fastest test: ask the site for an address nobody has ever linked to, such as /this-page-does-not-exist-7f3a, and look at the status code. Our website status checker and HTTP headers checker show it, or from a terminal:
curl -sI https://example.com/this-page-does-not-exist-7f3a | head -n 1
HTTP/2 404or410: the site handles missing pages correctly.HTTP/2 200: every missing URL on the site is a soft 404.HTTP/2 301or302: follow the redirect (the redirect checker shows every hop). If it lands on the homepage, you have pattern 2 above.
The 404 page check in every Semhack audit does exactly this, with a random path on the audited site: it passes on 404 or 410, fails on a 2xx status, and warns when the missing page redirects or returns something else.
Check Search Console
In Search Console, open Indexing → Pages and look for the reason Soft 404 in the list of reasons pages aren't indexed. Click it to see example URLs. Use URL Inspection on one of them to see what Google fetched.
Search Console only lists URLs Google has crawled and decided about, so treat it as confirmation, not a complete list.
Crawl the site
A crawl finds soft 404s that no-one has reported yet, because it reaches pages through your own links. Look for pages that answer 200 but whose title or main heading reads like an error: "404", "Page not found", "This page doesn't exist".
Semhack's site audit does this on every page it crawls: pages that return 200 while their title or H1 looks like an error page (in English and several other languages) are listed as Possible soft 404s. The word "possible" matters. An article titled "Page not found errors, explained" matches the pattern without being an error, so check each one before you change anything.
Read your server logs
Logs show which URLs crawlers and visitors actually request. Look for URLs that return 200 with an unusually small response size, or a single template, across many different paths.
How to fix them
The right fix depends on whether the page should exist.
| The URL… | Answer with | Why |
|---|---|---|
| …never existed, or the content is simply missing | 404 Not Found | The standard answer. Keep a helpful error page, just send it with the right status |
| …existed and was removed on purpose, with no replacement | 410 Gone | Says the removal is deliberate. Search engines treat 404 and 410 very similarly; 410 is the more explicit of the two |
| …has a real replacement with the same purpose | 301 to that page | Visitors and links reach the equivalent page. Don't redirect to the homepage or to a loosely related page |
| …is a real page with too little on it | 200, with real content, or noindex | Add what's missing, merge it into a stronger page, or keep it out of the index |
Sending the right status
- nginx: use
error_page 404 /404.html;, without=200. - Apache: use a local path, as in
ErrorDocument 404 /404.html. With a full URL (ErrorDocument 404 https://example.com/404.html), Apache redirects to it instead, and the visitor never gets a 404 status. - Frameworks: most have a built-in way to stop rendering and answer 404 from the server, such as
notFound()in Next.js orabort(404)in Laravel and Flask. Use it in the route that loads the content, as soon as you know the item doesn't exist. - JavaScript apps without server rendering: Google's JavaScript SEO guide suggests two options when the status can't change: redirect to a URL where the server does return 404, or add
<meta name="robots" content="noindex">to the page when the app shows its error view.
Old URLs you no longer want
If your domain hosted something else before, crawlers may keep asking for addresses that have nothing to do with your site today. Don't redirect those to your homepage. Answer 410 and let them drop out. On semhack.com, for example, the URLs left over from the domain's previous owner answer 410 Gone.
Check your work
After a fix, repeat the tests: request a made-up URL again, check the status of a few previously affected pages, and recrawl the site. In Search Console, open the Soft 404 reason in the Pages report and click Validate fix so Google rechecks the listed URLs. Expect the count to fall over the following weeks rather than overnight; Google has to recrawl each URL first.