DEV Community

Bracketly
Bracketly

Posted on

The Silent Cloudflare Pages Bug That Was Quietly Hurting My SEO

The Silent Cloudflare Pages Bug That Was Quietly Hurting My SEO

While building a broken-link checker for Bracketly (a small free dev-tools site), I found something I wasn't expecting: every nonexistent URL on the site — /literally-anything-i-typed, /tools/does-not-exist, whatever — was returning HTTP 200, with the homepage's content, instead of a 404.

Why this happens

Cloudflare Pages has a fallback behavior for unmatched routes: if your deployed site has no 404.html, it serves index.html for any path it can't otherwise resolve — but critically, it does this with a 200 status code, not 404. This is the classic SPA-router pattern (makes sense for a client-side-routed React/Vue app where you want every path to load index.html and let JS take over routing). It's the wrong default for a plain static multi-page site, and if you never explicitly add a 404.html, you get it silently, with zero warning.

I only noticed because I was building a script to curl every URL in my sitemap and flag non-200 responses — and a deliberately-broken test URL came back green.

Why it's worse than it looks

This is what's sometimes called a "soft 404" — a page that should be an error but returns success. Search engines treat this specially, and not kindly:

  • Google's crawler explicitly detects soft-404 patterns (repeated identical content served at different URLs with a 200 status) and can flag the pattern site-wide, not just the one URL
  • Every broken/mistyped/old link pointing at your site becomes a duplicate-content page in Google's eyes, all serving the same homepage
  • It dilutes whatever ranking signal your actual homepage has, since Google now sees N copies of it at different URLs

For a site that had literally zero custom 404 handling, this meant any crawled dead link — a typo'd URL, an old removed page, a bot probing random paths — was quietly generating homepage duplicates in the index.

The fix

Trivial once you know to look for it. In Astro (or basically any static site generator), you just need a page that generates 404.html:

---
// src/pages/404.astro
import BaseLayout from '../layouts/BaseLayout.astro';
---
<BaseLayout title="Page Not Found" description="...">
  <h1>404</h1>
  <p>This page doesn't exist.</p>
</BaseLayout>
Enter fullscreen mode Exit fullscreen mode

Astro (and most SSGs) automatically emits this as dist/404.html, and Cloudflare Pages automatically serves it with a genuine 404 status for any unmatched route once it exists — no config needed, just the file being present.

$ curl -o /dev/null -w "%{http_code}" https://example.com/nonexistent-page
# before: 200
# after:  404
Enter fullscreen mode Exit fullscreen mode

The lesson

If you're deploying a static site to Cloudflare Pages, Vercel, Netlify, or similar — check right now whether a random broken URL on your site returns 404 or 200. It's a two-second check and a five-minute fix, but it's exactly the kind of thing that never shows up unless you go looking, since the page looks completely normal (it's literally rendering your homepage) — there's no visible error to notice.

Source for the actual fix: https://github.com/GRimkiller360/bracketly

Top comments (0)