All posts
technical SEO

Soft 404 Errors: When a Real URL Looks Like a Missing Page

A soft 404 means your server said 200 OK but Google saw a missing page. Learn to decide between restoring, redirecting, or returning a real 404 or 410.

By

TL;DR A soft 404 is a status-code mismatch: your server answers 200 OK, but what Google sees looks like an error or an empty page. The fix depends on intent. If the page should exist, make it render real content; if it moved, redirect it to the closest equivalent; if it's gone, return an honest 404 or 410 instead of dumping it on the homepage.

A founder deletes an integration with a tool that shut down. The integration page stays live, because the route is dynamic and the template still renders: header, nav, a heading that says "Integration not found," footer. The server returns 200. Two months later that URL, and a dozen others like it, show up in Search Console as Soft 404.

From the founder's side, nothing is broken. The page loads. That's the problem. The server said "here is a successful page" and the page itself said "there's nothing here." Google believed the page.

This post is about that contradiction: where it comes from on small SaaS sites, and how to pick the right fix instead of the reflexive one. If you're still figuring out which indexing stage a URL is failing at, my diagnostic for a website not showing up on Google is the better starting point.

What is a soft 404?

Google's Page indexing report help defines it in one line: the page "returns a user-friendly 'not found' message but not a 404 HTTP response code."

Google's HTTP status code documentation widens that: "If the content suggests an error for Google Search, an empty page or an error message, Search Console will show a soft 404 error." A success code gets the page considered for indexing, nothing more.

So soft 404 errors cover two situations that look alike in the report but have opposite fixes:

  1. The page really is gone, but the server still says 200. The status code is lying.
  2. The page should exist, but Google received something that looks empty or broken. The content is failing.

The report doesn't tell you which one you have. You have to look.

Soft 404 vs 404

The difference between 404 and soft 404 is honesty. A real 404 is the server telling the truth: this URL has nothing. Google's docs say URLs returning a 4xx aren't indexed, and already-indexed ones get removed (HTTP status codes). That's a clean outcome.

A soft 404 is the server saying "success" while the page says "missing." Google has to guess, and the URL sits in a report instead of resolving one way or the other.

Here's the part founders misread: a 404 isn't a problem to fix by default. The Page indexing help says "404 responses are not necessarily a problem, if the page has been removed without any replacement." Seeing Not found (404) in Search Console is often the system working. Seeing Soft 404 is the system confused.

SignalServer saysPage showsWhat Google does
Healthy page200Real contentEligible for indexing
Real 404 or 410404 or 410AnythingNot indexed, removed if it was
Soft 404, page is gone200Not found messageFlags it, won't index
Soft 404, page is broken200Empty or failed renderFlags it, won't index

Where soft 404 errors come from on SaaS sites

On a small SaaS site, I'd look at these patterns first.

Dynamic routes with no existence check. A blog at a slug route or an integration directory that renders the template whether or not the record exists. Deleted posts, typo'd slugs, and retired integrations all return 200 with a "not found" message.

Empty list pages. A tag page with zero posts, a changelog filter with no results, an integration category that's been emptied out. The page technically exists. It says, in effect, "nothing here."

Client-side rendering that fails for Googlebot. The HTML shell arrives with a spinner, the JavaScript that fetches the content errors out or depends on a blocked API, and Google renders a near-empty page. Google's JavaScript SEO basics addresses this directly for single-page apps, because the server can't know whether a record exists when it only ships a shell.

Thin placeholder pages. An integration page that's just a logo and "Coming soon." A docs stub. These return 200 legitimately, but the content is so close to empty that Google can read it as an error page.

Mass redirects to the homepage. After a cleanup, every removed URL gets pointed at the homepage. Google's site move guidance warns against this: "Don't redirect many old URLs to one irrelevant single URL destination, such as the home page of the new site. This can confuse users and might be treated as a soft 404 error."

That last one usually comes from good intentions about "not losing link equity."

How to confirm which kind of soft 404 you have

In Search Console, open the Soft 404 row of the Page indexing report and look at the example URLs. For each one, run it through URL Inspection and use Test live URL, then View tested page.

Three questions, in order:

  1. Should this URL exist? Check your CMS, your database, your sitemap. Did you delete or rename it?
  2. What status code does it return? Check the HTTP response in the tested page view, or run a HEAD request from your terminal.
  3. What did Google render? Look at the screenshot and search the rendered HTML for a sentence from the middle of the page. If the body text is missing, Google saw an empty shell.

If the URL shouldn't exist and returns 200, the status code is wrong. If it should exist and the render is empty, the content pipeline is wrong. If it should exist and the render looks full, the page is probably too thin to read as a real page.

How to fix soft 404: restore, redirect, or remove

There's no default fix. The right answer depends on what the URL was for and whether anyone still needs it.

SituationFix
Page should exist, renders empty for GoogleRestore: fix rendering or server-side data
Page should exist, content is a stubRestore: add real content, or noindex until it's ready
Content moved or was merged into another pageMeaningful redirect to the closest equivalent
Content is gone with no replacementReturn 404 or 410
Empty filter, tag, or list pageReturn 404 when empty, or noindex, or stop generating it

Restore when the page should exist

If URL Inspection shows a spinner or a blank body, fix the render before anything else. For a JavaScript-heavy page, the fastest win is usually getting the main content into the server response instead of fetching it after load. Once the rendered HTML contains the real body, the soft 404 has no reason to persist.

For stub pages, be honest about whether the page is ready. An integration page with a logo and one sentence isn't a page yet. Either write what the integration actually does, what data syncs, and how to set it up, or keep the page out of the index until you have. A dozen real integration pages beat a directory full of placeholders.

Redirect only to a real equivalent

A 301 is right when the content lives somewhere else now. The Page indexing help says that if a page has moved, you should use a 301 redirect to the new location. Google also notes that when it follows a redirect, content from the redirecting URL is ignored and the target is processed instead (HTTP status codes).

Good redirects on a SaaS site look like:

  • Two overlapping blog posts merged into one: redirect the weaker one to the merged post.
  • An integration renamed after the partner rebranded: redirect the old slug to the new one.
  • A deprecated feature page replaced by a broader one that covers the same job: redirect to the replacement.

Bad redirect: a retired integration pointed at the homepage. Nobody searching for that integration wants your homepage, and Google's site-move guidance says it may be treated as a soft 404 anyway. You've swapped one soft 404 for another and hidden the evidence.

My test: would a person who clicked the old link say "yes, this is what I was looking for" when they land? If not, don't redirect.

Return a real 404 or 410 when it's gone

If the integration partner shut down and there's no replacement, the honest answer is 404 or 410. Google's docs say all 4xx errors except 429 are treated the same: crawlers "inform the next processing system that the content doesn't exist" (HTTP status codes). So for Google Search, picking 410 over 404 is a matter of preference, not a ranking lever.

Keep the 404 page helpful for humans. Search, links to your main sections, a link to the integrations directory. A useful 404 page is fine. A useful 404 page served with a 200 status is the soft 404.

Then clean up the trail. Remove the dead URL from your sitemap and from internal links. A deleted post that's still linked from five other posts keeps getting rediscovered, and a page with no links at all is the opposite problem, which I covered in finding orphan pages your internal links forgot.

Next.js soft 404: the streaming trap

A lot of indie SaaS sites run on Next.js, so this one deserves its own section. The Next.js notFound docs say calling notFound() renders the 404 UI and injects a robots noindex meta tag.

The catch is status codes. If the existence check runs inside a Suspense boundary, the response has already started streaming as a 200, and in the docs' words, "the status can't change once streaming has started." The noindex tag keeps the page out of search results, but the status still says 200. To return a real 404, the docs say the check has to happen before the response streams.

The practical version: look up the record at the top of the route, before any Suspense boundary, and call notFound() there.

const post = await getPost(slug)
if (!post) {
  notFound()
}

Then verify it. Fetch a known-bad slug and check the status code, not the page text. The page will look identical either way; only the header tells you whether you fixed it.

For pure client-side apps with no server check, Google's JavaScript SEO basics gives two options: redirect with JavaScript to a URL that returns a real 404 (for example a not-found route), or add a noindex robots meta tag with JavaScript on error pages:

<meta name="robots" content="noindex">

Validating the fix

After you've fixed a batch, use Validate fix in the Page indexing report. Google's help says validation typically takes up to two weeks and it emails you about progress (Page indexing report).

Don't expect the count to hit zero and stay there. As long as you publish, retire, and rename pages, a few will turn up. What matters is that each URL in the report is there because of a decision you haven't made yet, not one you made wrong.

The root cause is usually a content decision, not a code bug

Most soft 404s I've traced on small sites started as a content decision nobody finished. A post was deleted but nobody decided where its readers should go. An integration template went live before most partners had real pages. A category was created for a content plan that never shipped.

That's why I treat the soft 404 report as the tail end of a content audit. When you prune, merge, or retire posts, decide the fate of each URL at the same moment: keep, merge and redirect, or remove with a 404. My guide on what to do with content audit results walks through that decision per page. Do it there, and most soft 404s never appear.

The same logic runs upstream. The fewer placeholder and near-duplicate pages you create, the fewer you'll need to clean up later. That's part of why I'm building Boomranq to plan a small number of winnable pages rather than a big grid of templated ones: every URL on a low-authority site should have a reason to exist. If Google is also skipping pages that do return real content, the neighboring statuses are covered in crawled currently not indexed, discovered currently not indexed, and duplicate without user-selected canonical.

A soft 404 is Google asking a simple question your site hasn't answered: does this page exist or not? Answer it with the status code, not just the copy.

Want this planned for your site?

Boomranq turns your product into a sequenced 30-day calendar built around what your site can actually rank for. Join the waitlist for early access.

No spam · One email when we launch · Unsubscribe anytime