My pages looked fine in a browser. Google was indexing them. Then I read the HTML the way a crawler reads it, with no JavaScript:
curl -s https://your-site.com/some-page -A 'OAI-SearchBot/1.0' There was a header, an empty slot and a footer. The article came after the footer, inside <div hidden id="S:1">. A small inline script moves it into the slot when the page loads.
Googlebot runs that script. A crawler that doesn't run JavaScript gets a hidden block at the bottom of the page. I can't see inside every crawler to know what it does with that. I didn't want to bet my pages on it.
The cause
One wrapper I had written on purpose:
<Suspense fallback={null}> <Content params={params} /> </Suspense> I assumed a boundary that finishes at build time gets inlined. Not always. React has an option called progressiveChunkSize, 12,800 bytes by default. A boundary bigger than that gets outlined: the slot goes out first, the content later. The rule is about size, not about waiting.
You can prove it with nothing async at all. I rendered a plain Suspense boundary with React 19.3's renderToPipeableStream:
| Boundary size | Article hidden after the footer? |
|---|---|
| 2,000 bytes | No |
| 12,000 bytes | No |
| 14,000 bytes | Yes |
| 40,000 bytes | Yes |
40,000 bytes, with progressiveChunkSize raised | No |
The limit counts HTML bytes, not words. Tailwind classes count. Even my shortest page, a list of five calculators, crossed it.
How to check
Find your <h1> in the raw HTML. If <div hidden id="S: comes right before it, you have this.
The fix
Stop wrapping the article. With Cache Components on, reading params outside Suspense fails the instant navigation check, so routes with a dynamic param also need:
export const instant = false; That turns off a check, not prerendering. My pages still answer x-nextjs-prerender: 1.
Most of my fallbacks were null, so I lost nothing there. A blank page was never instant in any way a person would value. On my docs I did give up a loading skeleton. I took that trade.
Before and after
On a calorie page on Kallo, the words outside the hidden block went from 107 to 779. Nothing is hidden now.
No test caught this. The types were fine, the page looked right, and Google was happy. It only shows up if you read the bytes.
Check your own site. It takes ten seconds.
