Technical SEO

Soft 404 in Search Console: what triggers it and the fix for each case

Google reports a soft 404 when a page answers 200 but looks empty or like an error. Here is how to tell a real missing page from a thin template, and what to change in each case.

By SEOFix TeamPublished Updated
2,219 words · 10 min readMarkdown
Soft 404 in Search Console: what triggers it and the fix for each case

A soft 404 in Search Console means your server answered 200 OK, but Google read the page as missing, empty or broken. Google's HTTP status code documentation puts it plainly: "If the content suggests an error for Google Search, an empty page or an error message, Search Console will show a soft 404 error." The page is not indexed. The fix depends on which of two situations you are in: the page really has nothing to show, so it should return a real 404 (or 410), or the page is fine but looks empty to Google, so it needs more content of its own.

Almost every soft 404 we see comes from one of four templates: empty search and filter results, deleted records that render a "not found" message with a 200, out-of-stock or expired items, and thin pages where the shared layout outweighs the page's own text. Below is how to tell which one you have, and the fix for each.

Google's behaviour quoted here comes from the Search Central and Search Console help pages, checked on 2 November 2026.

What Google says a soft 404 is

The Page indexing report help defines the status like this:

The page request returns what we think is a soft 404 response. This means that it returns a user-friendly "not found" message but not a 404 HTTP response code.

Its advice is two-sided: "We recommend returning a 404 response code for truly 'not found' pages and adding more information on the page to let us know that it is not a soft 404."

Three more points from Google's docs:

  • It is a judgment about content, not about headers. Nothing in your response says "soft 404". Google infers it from what the page shows after rendering.
  • Soft 404s cost crawl budget. Google's crawl budget guide says "soft 404 pages will continue to be crawled, and waste your budget." A real 404 is, in the same guide's words, "a strong signal not to crawl that URL again."
  • Redirecting dead URLs to the homepage counts as one. Google's 404 help page lists returning a non-404 code for a missing page, or "redirecting users to another page, such as the homepage, instead of returning a 404", as a soft 404.

Step 1: find out what Google saw

Before you change code, look at the page the way Googlebot rendered it.

  1. In Search Console, open Indexing → Pages, then the Soft 404 row under "Why pages aren't indexed". The example table shows up to 1,000 URLs.
  2. Click the inspect icon on a few URLs from each URL pattern (for example /search?q=, /products/…, /jobs/…).
  3. Click Test live URL, then View tested page. The help page for URL Inspection says the live test shows "a screenshot of the rendered page, the raw HTML returned, the HTTP headers, JavaScript console output, and any page resources loaded".

Look at three things in the tested page:

  • Screenshot. Is the main area empty, a spinner, or an error message?
  • HTML. Search it for strings like "no results", "not found", "0 jobs", "no longer available", "something went wrong".
  • Console output. A failed API call during rendering often leaves a client-rendered page empty, and the error shows up here.

Then fetch the same URL yourself to see the status and the visible text a crawler gets without JavaScript:

# status code and size
curl -s -o /dev/null -w '%{http_code} %{size_download} bytes\n' \
  -A 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)' \
  https://example.com/jobs/data-analyst-123

# rough visible word count of the server HTML (scripts and tags stripped)
curl -s https://example.com/jobs/data-analyst-123 \
  | sed -e 's/<script[^>]*>.*<\/script>//g' -e 's/<[^>]*>/ /g' | wc -w

Group the URLs by template before deciding anything. A soft 404 is almost always a template problem, so 500 flagged URLs usually come down to two or three causes.

Cause 1: empty search, filter and category pages

What it looks like: /search?q=blue+widget, /shoes?color=green&size=13 or /category/winter-2019/ answer 200 with "No results found" or an empty grid. Google crawls them because something links to them: faceted navigation, a sitemap, an old internal link.

What to do: return a 404 when the result set is empty. Google's faceted navigation guide says exactly this:

Return an HTTP 404 status code when a filter combination doesn't return results.

It adds that the same applies to "duplicate filters or otherwise nonsensical filter combinations, and nonexistent pagination URLs", and that you should not redirect those URLs to a shared "not found" page. Serve the 404 at the URL where it happened.

Internal site search is a separate question. Most sites don't want search result pages indexed at all, so a noindex on every search page (or a robots.txt Disallow for the search path, if you'd rather Google not crawl them at all) is cleaner than tuning which ones 404.

WordPress

WordPress returns 200 for some empty archives on purpose. In the core WP::handle_404() method, when a query finds no posts and isn't paged, it does not set a 404 for: an author who exists on the site, a tag, category, taxonomy or post type archive that matched an existing object, the home page, search results and feeds. An empty category page and an empty search page therefore answer 200, and those are classic soft 404 sources.

Core lets you override this with the pre_handle_404 filter. This sends a real 404 for empty taxonomy archives and leaves everything else to core:

// functions.php or a small mu-plugin
add_filter( 'pre_handle_404', function ( $preempt, $wp_query ) {
    if ( $preempt ) {
        return $preempt;
    }
    $is_empty_archive = ( is_category() || is_tag() || is_tax() )
        && ! $wp_query->posts
        && ! is_paged();

    if ( $is_empty_archive ) {
        $wp_query->set_404();
        status_header( 404 );
        nocache_headers();
        return true; // stop core's own handling
    }
    return false;
}, 10, 2 );

For search, add noindex instead. Most SEO plugins already noindex search pages; check the setting before writing code.

Next.js (App Router)

Call notFound() when the query comes back empty. The Next.js docs say it "renders a Next.js 404 page" and that Next.js "also injects a <meta name="robots" content="noindex" /> tag".

// app/jobs/[city]/page.tsx
import { notFound } from 'next/navigation'

export default async function CityJobs({ params }: { params: Promise<{ city: string }> }) {
  const { city } = await params
  const jobs = await getJobs({ city })
  if (jobs.length === 0) notFound()
  return <JobList jobs={jobs} />
}

The same docs say that if the response has already started streaming from a <Suspense> boundary when notFound() runs, "it keeps its 200 status" (Next.js still adds the noindex tag). If you want a real 404 status, do the existence check before anything streams: at the top of the page component, outside <Suspense>, or in Proxy.

Cause 2: deleted records that render "not found" with a 200

What it looks like: /products/12345 for a product that was deleted. The route still matches, the database lookup returns nothing, and the template prints "This product could not be found" in a 200 response. On single-page apps the server returns the app shell with 200 for every path, and JavaScript draws the error.

What to do: return 404 (or 410 if you know it is gone for good) from the server. Google's 404 help page is explicit: "If you have permanently deleted content without intending to replace it with newer, related content, let the old URL return a 404 or 410. Currently Google treats 410s (Gone) the same as 404s (Not found)." If there is a real replacement, 301 to it instead. Not to the homepage.

On a client-rendered single-page app where the server can't know the status, Google's JavaScript SEO basics give two options:

  • Use a JavaScript redirect to a URL for which the server responds with a 404 (for example /not-found).
  • Add <meta name="robots" content="noindex"> to error pages using JavaScript.
// Google's noindex approach for client-rendered error states
fetch(`/api/products/${productId}`)
  .then((res) => res.json())
  .then((product) => {
    if (product.exists) {
      showProductDetails(product)
    } else {
      const meta = document.createElement('meta')
      meta.name = 'robots'
      meta.content = 'noindex'
      document.head.appendChild(meta)
    }
  })

Server rendering is still the better fix if you have the option. Both workarounds depend on Google rendering the page successfully.

Cause 3: out-of-stock products and expired listings

What it looks like: a product page that shows "Currently unavailable" and nothing else, or a job ad that collapses to "This position has been filled" once it expires.

Google's docs don't single out out-of-stock pages. What they define is the general rule: a 200 page whose content looks like "an empty page or an error message" becomes a soft 404. A product page reduced to an unavailability notice matches that description. So the decision is about what the page should be:

SituationFix
Temporarily out of stock, coming backKeep the full page: description, specs, photos, reviews, price. Mark availability in structured data (Google's merchant listing docs list https://schema.org/OutOfStock). Add related products.
Discontinued, with a successor301 to the successor product.
Discontinued, no replacementReturn 404 or 410. Remove it from the sitemap and internal links.
Expired job, event or listingReturn 404/410, or 301 to a closely matching live listing if one exists. A redirect to a generic category is the homepage problem on a smaller scale.

What doesn't work is keeping the URL alive as an empty shell "to keep the link equity". Google reads the shell as a missing page anyway, and you pay for the crawl.

Cause 4: real pages that look empty

This is the case where the page is legitimate and should be indexed, but Google still calls it a soft 404. It happens most on programmatic sites: thousands of location, profile or listing pages built from one template, each with a heading, two lines of unique text and a large shared header, sidebar and footer.

How to confirm it: in the live test screenshot the page looks normal to you, and the HTML has no error string. The page's own content is small next to the layout around it.

What to do:

  • Put the unique content first. The page's own facts (the job description, the product specs, the business details) should come before shared blocks in the HTML.
  • Add real data, not filler. Fields you already have in the database: salary range, location details, opening hours, related items in the same category. Spun text doesn't help.
  • Merge the thinnest pages. If 300 location pages each list one item, a single page for the region may serve users better than 300 near-empty ones.
  • Check that rendering works. If the content comes from a client-side API call, a failed or slow call during Google's render leaves the page empty. The console output in View tested page shows it.

A page that is thin because the data is thin may be better off out of the index entirely. Add noindex to pages below a content threshold you choose (for example, a city page with zero listings), and keep them out of the sitemap.

What not to do

  • Don't redirect dead URLs to the homepage. Google's 404 help page names it as a soft 404 cause: "Don't create fake content, redirect to your homepage, or use robots.txt to block 404s."
  • Don't block soft 404 URLs in robots.txt. Google can no longer fetch them, so it never sees the 404 or noindex you add later.
  • Don't add filler text to error pages to make them "look less empty". If the page has nothing for the user, a 404 is the honest answer.
  • Don't request indexing URL by URL. Fix the template, deploy, then validate the issue once.

After the fix: validate

  1. Deploy and purge your CDN cache for the affected paths.
  2. Spot-check with curl: missing pages should now answer 404 or 410, real pages 200 with their content in the HTML.
  3. Run Test live URL on two or three examples per template.
  4. In the Page indexing report, open Soft 404 and click Validate fix. URLs that now return 404 will move to Not found (404), which is the correct state for them. Our post on Validate fix vs Verify fix explains the validation states and why it takes about two weeks.

Soft 404 is one of the reasons the crawled / discovered – currently not indexed triage runs into too: on a template-built site, the same thin template often produces both statuses.

How SEOFix helps find the templates

Two SEOFix checks map onto soft 404 causes. THIN_CONTENT flags indexable pages whose visible body text is under 100 words (on-page checks), which catches empty result pages and thin templates on your side before Google reports them. With Search Console connected, the not-indexed triage groups pages Google doesn't index by URL pattern. Pages that answer 200 with under 150 words, or whose title or first H1 reads like an empty result ("no results", "0 jobs"), land in Thin or empty, with the advice to noindex them or drop them from the sitemap. A page Google calls "Soft 404" that has 150 or more words gets the reason google_soft_404 and an improve_content action: put content unique to each page at the top.

FAQ

Is a soft 404 bad for my rankings?

The flagged URL isn't indexed, so it can't rank. If it's a page that should exist, that's lost traffic. If it's an empty filter page, the only cost is crawl budget, and returning a real 404 fixes that.

Should I return 404 or 410?

Either. Google's 404 help page says it currently treats 410 the same as 404. Use 410 when you know a page is gone for good and your framework makes it easy. Otherwise 404 is fine.

Why does Google call a page with real content a soft 404?

Usually the content isn't in what Google rendered (a client-side fetch failed or timed out), or the page's own text is tiny next to the shared layout. Check the live test screenshot and console output first.

Can I get a soft 404 on a redirect?

Yes. Redirecting a removed page to the homepage or to an unrelated page is one of the soft 404 causes Google names. Redirect to a close replacement, or return 404.


To find empty and thin templates across your whole site in one pass, run a free SEOFix audit (up to 500 pages, no card). With Search Console connected, the not-indexed triage groups Google's soft 404s by URL pattern and gives you one fix per group.

ShareXLinkedIn