Real incident · Logged as it happened, not written after the fact

The Cloudflare Pages .html URL Trap (And How We Almost Made It Worse)

17 pages stuck in redirect limbo. Indexed pages flat at 20 for three weeks while impressions dropped. Then our first attempted fix caused a real live outage. Here's the actual GSC data, the mistake, and the real fix — including the part where we got it backwards the first time.

Incident window: Aug 21 – Sep 20, 2026 · Fix deployed Sep 20 · Results section will be updated as real data comes in

Indexed pages sat flat at 20 for three straight weeks. Not-indexed climbed from 32 to 40.

Every guide shipped since late August landed in the not-indexed pile instead of the indexed one — and impressions fell from 55/day to single digits as a result.

What this is and isn't This is a real technical mistake, logged in real time from our own Google Search Console exports — not a tutorial written after the fact by someone who got it right the first try. We got the fix backwards initially and took the site down for a few minutes doing it. The "did it actually work" section is still pending as of publish, because it's only been a few days. We'll update it honestly either way.
Part 1

The trap: what Cloudflare Pages actually does with .html

If you deploy a static site to Cloudflare Pages, every foo.html file is automatically served at both /foo.html and the clean URL /foo — and by default, Cloudflare treats the clean URL as canonical, silently redirecting requests for /foo.html over to /foo. This behavior isn't loudly documented anywhere you'd naturally find it before it bites you.

That's fine, as long as your site agrees with it. Ours didn't. Every canonical tag, every sitemap entry, and every internal link across roughly 24 pages pointed to the .html version — built that way, ironically, as an earlier fix for a different duplicate-URL problem (an http/https split resolved with canonical tags and Cloudflare's HTTPS enforcement). Nobody had connected that fix to how Cloudflare's own clean-URL redirect actually behaves.

⚠️ The signal this sends Google

Google crawls a .html URL from your sitemap, gets redirected by Cloudflare to the clean URL, and then checks your canonical tag — which claims the .html version was the "real" one all along. That's a contradiction Google can't resolve cleanly, and it shows up in Search Console as exactly what it is: pages it can't confidently index.

Part 2

The real numbers that revealed it

We only found this because a routine Search Console Coverage export looked wrong. Here's what it actually showed, unedited.

DateNot indexedIndexedImpressions
Aug 21321731
Aug 28352055
Sep 4402012
Sep 1340208

The critical-issues breakdown from that same export made the cause obvious:

IssuePages
Page with redirect — validation Failed17
Alternate page with proper canonical tag5
Duplicate without user-selected canonical3
Discovered — currently not indexed11
Crawled — currently not indexed3
🚩 23 of 24 sitemap URLs used the .html form

A quick grep of our own sitemap confirmed it: 23 of 24 <loc> entries pointed to .html URLs. That's not one mistyped link — it's the entire site's URL structure disagreeing with what the hosting platform actually serves.

Part 3

The mistake: how our first fix caused an outage

Seeing one specific page — our top-performing guide — indexed twice with a huge position gap between the two versions (the .html form sitting at position 6.4, the clean URL buried at position 56.5), the first instinct was to add a redirect forcing the clean URL to the .html version, since that's what the canonical tag already claimed was correct:

/faceless-youtube-channel-guide  /faceless-youtube-channel-guide.html  301

This was backwards. Cloudflare Pages was already redirecting .html requests to the clean URL automatically, sitewide, by default. Adding a rule that redirected the clean URL back to .html created a loop: request the clean URL → redirected to .html → Cloudflare redirects that back to the clean URL → repeat. The page went down with ERR_TOO_MANY_REDIRECTS within minutes of deploying.

🚩 The real lesson here

We assumed the canonical tag reflected the platform's actual behavior, and built a fix on that assumption without first confirming what Cloudflare Pages does by default. It took a live outage to reveal the assumption was backwards. If you're debugging something similar, verify what your host actually does with a URL before writing a redirect rule that assumes it — a five-minute check that would have prevented this entirely.

Part 4

The actual fix

The _redirects rule was pulled immediately to stop the outage. The real fix went the other direction from the first attempt: instead of forcing everything to .html, every canonical tag, every sitemap entry, and every internal link across the site was changed to the extensionless form — matching what Cloudflare actually serves, instead of fighting it.

Concretely, that meant:

✅ Why this direction is right, and the other wasn't

Cloudflare's clean-URL redirect isn't something you can turn off with a canonical tag — it happens before your HTML is ever read. The only way to stop fighting it is to make your own URLs agree with it. Existing external links pointing to .html URLs (including ones already pinned on Pinterest) aren't affected — they still resolve, just through one redirect hop instead of zero.

Part 5

How to check if your own site has this

If you're on Cloudflare Pages with a static site, three quick checks:

Does your canonical tag match .html or clean URLs?Open a page's source and check the <link rel="canonical"> tag.
What does your sitemap actually list?Grep your sitemap.xml for .html — if most entries have it, you likely have this same mismatch.
What does a live request actually do?Visit a .html URL directly in a browser and watch whether it silently redirects to the clean version — that redirect is the platform's real answer, regardless of what your canonical tag claims.

If your sitemap and canonical tags already use the clean URL form, you don't have this problem. If they use .html like ours did, the fix in Part 4 is the same one we ran.

This is a live, ongoing fix — not a finished result yet

We'll update this page honestly once there's enough post-fix Search Console data to say whether it worked, including if it doesn't move the numbers the way we expect.

Follow the ongoing build log →
Sources & caveats

Source

  • Google Search Console — Coverage and Performance exports for theaibuildlab.com, pulled directly during the incident (Aug 21 – Sep 20, 2026). Raw numbers reproduced here, not estimates.

Caveats

This page was published only days after the fix was deployed. The Coverage and Performance numbers in Parts 1–3 are real and already confirmed. Whether the fix actually moves indexed-page counts and impressions back up is not yet confirmed as of publish — that section will be updated with real follow-up data once enough time has passed for Google to fully recrawl and re-evaluate the affected pages, which the previous canonical fix on this same site took several weeks to fully resolve.