A soft 404 is a URL that returns 200 OK while the page itself says, or looks like it says, "there is nothing here". Google works this out from the content, treats the URL like a missing page and keeps it out of the index. The fix depends on which side is wrong: if the page is really gone, return a real 404 or 410 (or a 301 to a true equivalent). If the page is real, find out why Googlebot saw an empty or error-like page and fix that.
Why the status code matters
A crawler relies on the status code to know what happened. 404 and 410 say "gone, drop this URL". 200 says "here is the content, consider indexing it". A friendly "Sorry, we couldn't find that page" served with a 200 is a contradiction, and Google resolves it by classifying the URL as a soft 404.
Google's documentation points out two costs:
- Crawling is wasted. Google's crawl budget guidance lists soft 404s among the things that eat into crawling on large sites, since these URLs keep getting crawled.
- Users get a poor result if such a page does slip into the index.
The third cost is the one that hurts most in practice: false positives. When a real page gets the label, it is out of the index until you work out what Googlebot saw.
Where to find them
- Indexing > Pages, under "Why pages aren't indexed", row Soft 404. Click it for up to 1,000 example URLs.
- URL Inspection on a single URL: "URL is not on Google", reason "Soft 404". (Through the URL Inspection API the
pageFetchStatefield readsSOFT_404.) - Filter the report to All submitted pages. A soft 404 on a URL in your sitemap is the high priority kind, since you have told Google that the page matters. Older Search Console versions called this "Submitted URL seems to be a Soft 404".
Diagnose: which kind do you have?
Ask one question per URL: should this page exist?
| Answer | Kind | Direction of the fix |
|---|---|---|
| No, it was removed or never existed | True soft 404 | Send the right status code |
| Yes, it is a real page with real content | False positive | Fix what Googlebot sees |
| Sort of: it exists but is empty right now | Empty state | Decide per template |
To confirm what is going on, check two things.
The status code. Run the URL through the bulk HTTP status checker or:
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.com/some-missing-page
Try a URL you know does not exist, such as /this-page-does-not-exist-123. If it prints 200, your site serves soft 404s for every mistyped URL, and the fix is global.
The rendered page. In URL Inspection click Test live URL, then View tested page, and look at the Screenshot and HTML tabs, plus More info > Page resources for anything that failed to load. This is what Google judged. If the screenshot shows a blank area, a spinner or an error message where your content should be, you have found the cause.
Causes and fixes
The page is gone but returns 200
The CMS or framework renders a "not found" template without setting the status. Single page applications are the classic case: the server returns the same index.html with 200 for every path, and the router shows a "not found" view on the client.
Fix on the server where possible:
// Express: real 404 for unknown routes
app.use((req, res) => {
res.status(404).render("not-found");
});
# Apache: custom error page with the correct status.
# Use a local path. A full URL here causes a redirect and a 200.
ErrorDocument 404 /not-found.html
# Nginx
error_page 404 /not-found.html;
For single page apps that cannot set a status per route, Google's JavaScript guidance offers two workarounds: redirect with JavaScript to a URL for which the server does return 404, or inject <meta name="robots" content="noindex"> into the error view. Server-side rendering that sets the correct status is the better long-term answer.
Choosing the status:
| Situation | Response |
|---|---|
| Page removed, no replacement | 404 or 410 |
| Page moved or replaced by a close equivalent | 301 to that page |
| Temporarily unavailable (maintenance, outage) | 503, ideally with Retry-After |
| Product temporarily out of stock | 200, keep the full page, mark availability |
Deleted pages redirect to the homepage
Bulk-redirecting removed URLs to / or to a top category is a widespread migration shortcut. Google commonly treats such redirects as soft 404s, because the destination does not replace what was there. Redirect one to one where a real equivalent exists, and let the rest return 404 or 410. A 404 for a page that is gone is not a fault. It is the honest answer.
Empty listings and zero-result pages
Category pages with no products, tag archives with no posts, internal search pages with "0 results", location pages with "no stores near you". They return 200 and contain nothing.
- Internal search results: keep them from being crawled at all with a robots.txt rule.
- Empty categories and tags: return 404 while empty, or
noindexthem, or do not generate them until they have content. Remove them from the sitemap and from navigation. - Filters that lead to zero results: do not link to them.
Thin real pages
A real page with so little unique content that, beside the header and footer, it resembles an empty template. A product with a name and a price, a profile page with one line, a stub article. Add the content the page is missing, or consolidate it into another page. This overlaps with thin content and indexing.
Error-like wording on a valid page
Google's classifier reads the text. A live page whose most prominent message is "no longer available", "not found", "0 items", "this listing has expired" or "sold out" can be classified as an error page. For expired listings and discontinued products that you keep online, lead with the useful content (specifications, alternatives, related items) and make the availability note secondary. If the page has no remaining value, return 404 or 410, or 301 to the successor product.
Content fails to load for Googlebot
This is the main source of false positives:
- JavaScript, CSS or API endpoints blocked by robots.txt, so the render is empty. Test the resource URLs with the robots.txt tester.
- API calls that fail or time out for Googlebot because of authentication, CORS, rate limiting or bot protection.
- Content that appears only after a click, a scroll or a consent choice.
- A server that responds to load with a lightweight error page and
200. - A failed database query that leaves the main area blank while the template renders normally.
The fix is whatever makes the main content present in the rendered HTML of the live test. See JavaScript SEO: rendering and indexing.
Redirects to a login or an error page
/account/orders redirects Googlebot to /login, which answers 200 with a form and nothing else. Google may label the original URL a soft 404. Private pages should simply be kept out of crawling with robots.txt, and should not be in the sitemap.
After the fix
For pages that are really gone: once the URL returns 404 or 410, it moves from "Soft 404" to "Not found (404)" in the report. That is the correct final state, not a new problem. Remove the URLs from the sitemap and fix internal links that still point to them, which you can find with the page link extractor on the pages that used to link there.
For false positives:
- Run Test live URL and check that the screenshot shows the full content.
- Click Request indexing.
- For a group, click Validate fix on the Soft 404 issue. Google says validation typically takes up to about two weeks and can take much longer.
If the label comes back after a recrawl, the page still looks empty or error-like to Google. Go back to the rendered HTML and compare it with a similar page that is indexed.
What not to do
- Do not redirect all 404s to the homepage. It converts clear signals into soft 404s.
- Do not block soft 404 URLs in robots.txt to clear the report. Google cannot then see the corrected status code, and the URLs linger.
- Do not return 404 for out of stock products that will return. You lose an indexed page for a temporary condition.
- Do not serve a 200 "maintenance" page during downtime. If Google crawls it, every URL looks identical and empty. Use 503.
- Do not pad thin pages with boilerplate. Text repeated on every page adds nothing unique.
Prevention checklist
- A made-up URL on your site returns 404, not 200 and not a redirect to the homepage
- The custom 404 page is helpful for people (search box, links) and still sends a 404 status
- Empty categories, tags and search pages are not indexable and not in the sitemap
- Removed content is redirected only to true equivalents
- Maintenance mode returns 503
- Main content is present in the rendered HTML without user interaction
- The sitemap lists only 200-status, indexable URLs with real content
Soft 404 on a real page is one of several "crawled but rejected" outcomes. If the page renders well and still is not indexed, continue with why is my page not indexed.
Frequently asked questions
- What is a soft 404?
- A soft 404 is a URL that tells the user the page does not exist, or shows little or no content, while returning a success status code such as 200. Google detects this from the page content, treats the URL like a missing page and does not index it.
- Are soft 404s bad for SEO?
- They are harmless when the page really is gone, although a proper 404 or 410 is cleaner and saves crawling. They are harmful when Google labels a real, valuable page as a soft 404, because that page is then kept out of the index.
- Should I return 404 or 410 for removed pages?
- Either works. Google treats both as signals that the page is gone and removes the URL from the index. A 410 states more explicitly that the removal is permanent, but in practice the difference is small. What matters is that you do not return 200.
- Why is my real page flagged as a soft 404?
- Usually because what Googlebot rendered looked empty or like an error: main content failed to load, a required script or API call was blocked, the page showed an out of stock or no results message, or there was very little content besides the template.
- Is redirecting deleted pages to the homepage a good idea?
- No. Google commonly treats redirects from a removed page to the homepage or another unrelated page as soft 404s, and users find it confusing. Redirect only to a close equivalent. If there is none, return 404 or 410.