On this page 10 sections
- A 404 that pretends to be a page
- The usual causes on small sites
- 200, 404, 410 and the one you actually mean
- Empty templates, search pages and faceted URLs
- How to find soft 404s
- How to fix them without breaking bookmarks
- What to watch in Search Console afterwards
- A short prevention checklist
- Key takeaways
- Frequently asked questions
This is a diagnosis and repair method for a small site, not a tour of a checker. The soft 404 checker and an indexability checker will help you confirm a URL; they will not decide the policy. I have had to be careful about this on sites that render everything as 200 because a front-end router “does not have” a status code unless you teach it one.
A 404 that pretends to be a page
HTTP status codes are the machine-readable part of the answer. A 404 means the resource is not here; a 410 means it is gone for good; a 200 means here it is. A human-readable “Page not found” heading on a 200 response is a page, as far as the protocol is concerned. That is a soft 404.
Search engines document this class of problem — Google’s notes on soft 404s are the ones I check — because they see a lot of it: custom error templates served as 200, empty category pages, parameter URLs that always succeed, and SPA routes that never fail. Their systems may treat the URL as not found even though your logs look clean.
Why it matters on a small site:
- You cannot see it in a naive log of 404s, because there are none.
- The URL may appear in Search Console as a soft 404 or as “crawled — currently not indexed”, which is easy to ignore if you only watch ranks.
- Internal links and sitemaps can keep offering the URL as if it were a real document.
- A migration or a client-side router can turn thousands of typo URLs into 200s overnight.
A true 404 page can still be helpful and on-brand. It just has to be a 404 (or 410). Helpful copy and a status code are not alternatives.
The usual causes on small sites
The patterns I see most often:
- A custom error template served as 200, especially on a static host, a Worker, or a single-page app that falls back to
index.htmlfor every path. The HTML says not found; the status says OK. - CMS or shop empty states. A category, tag, or author archive with zero items still returns 200, sometimes with the words “no posts found”.
- Internal search result pages at URLs like
/search?q=…, always 200, often with no results, often accidentally left indexable. - Faceted or filtered listings that can be combined into a URL with no matching products, still 200.
- Soft deletions. You unpublished an article, but the old path now renders a generic “this article is no longer available” page with a 200, and it is still in the sitemap or in a leftover internal link.
- Redirects to a “not found” page that is 200, or a catch-all 301 to the homepage, which can also be interpreted as a soft 404 because the homepage is clearly not a replacement. The migration checklist is explicit about this for a reason.
- Placeholder or coming-soon URLs published too early, with almost no content, linked from the navigation.
JavaScript-rendered sites add a twist: the first response might be a 200 shell, and the “not found” state appears only after a fetch. A crawler that does not wait, or that does wait and still sees a thin not-found template, can reach the same conclusion. The status code of the document is the first thing to fix; a client-side 404 is not a 404.
200, 404, 410 and the one you actually mean
Pick the status that matches the truth, and use the HTTP status code reference if you need a reminder of the family. A short policy:
- 200 — this resource exists and is the document you want indexed, or it is deliberately
noindex(a thank-you page, a private account page). The body is the resource. - 301 / 308 — this resource has a successor. The destination is a real, equivalent page, not a generic not-found template and not, by default, the homepage.
- 302 / 307 — a temporary move. Rare for content you have taken down.
- 404 — we do not have this URL. It might come back, or you are not sure. The body can be a useful not-found page, but the status is 404.
- 410 — we do not have this URL and we do not intend to. Useful after a deliberate deletion, a closed shop category, or a retired campaign you do not want crawled again.
noindex is not a status code. It can keep a thin but real page (a search UI, a filter tool) out of the index while still returning 200 for users. It is the right tool when the page should exist and should not be treated as a document in Search. It is the wrong tool for a typo or a deleted article; those should 404 or 410, or 301 to a successor.
Do not invent a 200 “error” to keep the layout pretty. Every host I have used, including a Cloudflare Worker, can return a 404 with the same HTML skin as the rest of the site.
Empty templates, search pages and faceted URLs
These deserve a slightly longer treatment, because they are “real” routes in the product and still behave like soft 404s when they are empty.
Empty category or tag templates. If the category can have items, and today it has none, you can 200 + noindex (and keep it out of the sitemap) until it has content, or you can 404 if the category itself was a mistake. If it will never have items, 410 or remove the URL. Do not leave an indexable “no posts found” page in the sitemap.
Internal search. The search UI should usually be noindex, and it should not be linked as if each query were an article. Zero-result searches should still be 200 for the user (they did search) and not indexable. Do not let query URLs into the sitemap.
Faceted listings. Useful, stable filters can be real landing pages, with unique text and a 200, as discussed in the canonicals guide. Combinations that match nothing should 404, or 200 + noindex with a canonical back to a parent if that is a more honest description of a tool state. Infinite empty combinations will otherwise generate soft 404s at scale.
Paginated lists past the last page. /articles?page=99 should not 200 with an empty list if there are not 99 pages. 404, or redirect to the last real page, depending on how your lists work. ?page=1 should collapse to the canonical first page.
“This item was deleted” at the old slug. If you have a replacement, 301. If you do not, 410 or 404, with a search box or a link to the section if you want to be kind. A 200 that only says the item is gone is the textbook soft 404.
How to find soft 404s
You will not find them all in the 404 log. Use several sources.
- Search Console, in the page indexing report, for “soft 404” or similar “not found” classifications, and for “crawled — currently not indexed” on URLs whose body looks empty. URL inspection will tell you what Google last saw. This is the most direct signal, and it arrives after the fact.
- Your own crawl, compared to the sitemap. Every sitemap URL should be 200, indexable, and have a reasonable amount of unique content. A sitemap coverage diff is the mechanical part; you still have to open the empty-looking 200s. The soft 404 checker is designed for this kind of suspicion: a 200 whose content looks like an error or an empty state.
- A list of “not found”, “no results”, “no products”, “this page is missing” strings in the HTML of 200 responses. Grep a crawl, not the source only; a client-rendered message may only appear in the fetched page if your crawler runs JavaScript, so also look at the raw first response.
- Router fallbacks. If the host or the Worker serves
index.htmlwith 200 for unknown paths, request a deliberate nonsense path (/this-url-should-not-exist-test-404) and look at the status. If you get 200, you have a systemic soft 404, not a single typo. - After a migration, old URLs that now show a generic template. Compare the old inventory to the new statuses.
For a small site, I would request: the homepage, a real article, a known-deleted slug, a nonsense slug, an empty tag if you have tags, ?page=999, and a zero-result search. That half-dozen tells you more than a theory about the CMS.
How to fix them without breaking bookmarks
Fix the class, then the instances, and prefer a successor when one exists.
Systemic 200 fallbacks first. Teach the server, the Worker, or the static host to return 404 for unknown paths, with your not-found template. For a client-rendered app, that usually means the edge must know which paths exist, or it must ask an origin that can 404; a pure “always index.html” host will keep lying. Check that the 404 template itself is not linked in the sitemap and does not have a self-canonical to a pretty path you want indexed.
Deleted or moved pages. Build a small map: old slug to new slug, or to 410. A redirect generator is fine for a handful of rows; a full migration map is better if there are many. Bookmarks and inbound links then land on a real successor, which is kinder than a 404 and stronger than a 200 apology.
Empty listings and search. Take them out of the sitemap, add noindex if they must stay 200, or 404 when the collection itself does not exist. Add content or a unique introduction only when you intend the URL to be a real landing page — not a sentence of lorem to “thicken” a zero-result page. Do not invent text to game your way out of a soft 404 classification.
Sitemaps and internal links. Remove URLs you have 404ed or 410ed. Do not internally link to them. A leftover nav item is how a deleted page stays in a crawl.
Canonicals. A 200 not-found template should not canonicalise to itself as if it were a document, and it should not canonicalise to the homepage as a trick. Once it is a real 404, there should be no need for a canonical.
After the fix, request the URL uncached (and with any CDN cache purged). Confirm the status, the X-Robots-Tag or meta robots, and the absence of the URL from the sitemap. Then use URL inspection, and give crawlers time. Search Console will not update the same afternoon every time.
What to watch in Search Console afterwards
In the days and weeks after a fix:
- The affected URLs should move off the soft 404 classification, or drop out of the indexed set if they are now 404/410. A 301 to a successor should eventually consolidate on the destination.
- New soft 404s on a different pattern often mean you fixed one template and not the filter URLs, or a cache is still serving the old 200.
- “Crawled — currently not indexed” on a page you believe is strong may be a quality or duplication issue, not a soft 404. Do not treat every excluded URL as a status-code bug. Look at the body.
- Sitemap errors will tell you if you left a 404 in the sitemap.
Be patient, and be slightly suspicious of a sudden clean bill of health if your own fetch still shows 200 on a nonsense path. Your fetch is the ground truth for the status; Search Console is the ground truth for what Google last decided.
A short prevention checklist
- A deliberate nonsense URL returns 404, with a useful body, not 200.
- Deleted slugs 404, 410, or 301 to a real successor, and are off the sitemap.
- The 404 template is not in the sitemap and is not a 200.
- Empty categories, zero-result search and impossible facets are
noindexor 404, and are not in the sitemap. - Pagination past the last page does not 200 as an empty list.
- There is no catch-all 301 to the homepage for unknown paths.
- A SPA or Worker fallback cannot serve
index.htmlas 200 for unknown routes. - After each release that touches routing or templates, request the nonsense URL again.
That last item belongs in a release habit, the same way you would not ship an app with a broken URL handler and hope App Review does not notice. Routing is easy to break with a “helpful” fallback.
Key takeaways
- A soft 404 is a missing or empty page served as 200. Search engines may treat it as not found; your 404 logs will not show it.
- The usual causes are error templates served as 200, empty archives, indexable search and facet URLs, soft deletions, and SPA or Worker fallbacks.
- Use 404 or 410 for missing URLs, 301 when there is a successor, and 200 +
noindexonly for tools that should exist but should not be indexed. - Find them in Search Console, in a crawl of 200s that look empty, and by requesting a nonsense path.
- Fix the fallback first, then the instances, update sitemaps and links, and confirm the uncached status. Do not 301 everything to the homepage.
- Retest a nonsense URL after every routing change.
If you want a second pair of eyes on a soft 404 report, tell me about it.
Frequently asked questions
What is a soft 404 error?
It is a URL that looks, to a search engine, like a not-found or empty page, but is served as HTTP 200 OK. Typical examples are a “page not found” template with a success status, or a listing with no items and almost no unique content. Google may list it as a soft 404 in Search Console and decline to index it.
Why is a 404 page returning HTTP 200 a problem?
The protocol says the resource exists, and the text says it does not. Crawlers may treat the URL as not found anyway, keep rediscovering it, and lose trust in your other 200s. Users and tools that only look at the status will think the page is fine. Serve the same useful template with a 404 or 410 instead.
How do I find soft 404s on my website?
Check Search Console for soft 404 classifications, crawl your 200 URLs for empty or “not found” bodies, compare the sitemap to that crawl, and request a deliberate nonsense path. If that path is 200, the problem is systemic. A soft 404 checker can flag likely pages; you still have to inspect the status and the body.
Should a missing page be a 404 or a 410?
404 if the resource is not here and might return, or you are not sure. 410 if you have deliberately removed it and want that to be clear. Both are better than a 200 apology. If there is a successor, 301 to it instead.
Can a thin or empty page be treated as a soft 404?
Yes. A 200 page with almost no unique content — an empty category, an empty search, a placeholder — can be classified as a soft 404 even if it does not say “not found”. Give it a reason to exist and unique content, or take it out of the index, or stop serving it as an indexable 200.
Written by Lee Johnson. Published 10 November 2026.