Your Site Loads — But Google Sees Nothing
Friday deploy. Homepage loads fast in every browser. No errors. All metrics green. Monday morning: organic traffic down 38%. Search Console says "Discovered — currently not indexed." The page returns 200 OK. Logs are clean. APIs are fine. The homepage is effectively invisible to Google. This isn't downtime — it's a rendering failure.
A typical silent deindexing event:
200 OK
HTTP status
5 KB
HTML size
−38%
organic traffic
72 hr
to ranking drop
Every monitor stayed green. Nothing alerted. Traffic just disappeared.
On This Page
What's Actually Happening
Your browser shows a complete page because it executes JavaScript. Google sees the raw HTML response first, and that's what gets indexed.
In most SPAs, that initial HTML looks like this in production:
HTML size: 3 KB – 7 KB
Visible text: 0 – 120 characters
Body: <div id="root"></div> + <script> tags
Content: injected after hydration (if it succeeds)Googlebot fetches the HTML, may queue JS rendering for later (no guarantees), and indexes based on what's available early. If the initial HTML has no content, the page is treated as thin or empty.
What your browser shows
- • Full UI, navigation, content
- • Headings, paragraphs, product cards
- • ~35 KB DOM, 1,200+ words
- • Looks 100% healthy
What Google receives
- • Empty
<div id="root"> - • Script and stylesheet refs
- • ~5 KB total, <100 visible chars
- • No headings, no links, no content
That's not an SEO tweak problem. That's a broken page being served at the content layer while the network layer reports success.
Why Everything Looks Healthy
Nothing in your stack flags this. Every signal is green because every signal measures the wrong thing.
The request succeeded. Technically. But the output is useless. Your monitoring is telling the truth — about a system that's structurally incapable of catching empty pages.
Why Tools Miss This
Most tools measure systems, not content. They check status codes, latency, and error rates. They don't check HTML size, visible text length, or whether the DOM was actually built.
| Tool | What It Checks | Catches Empty HTML? |
|---|---|---|
| Uptime monitoring | Status code only — body ignored | No |
| APM / error tracking | Thrown exceptions, server errors | No |
| Backend logs | Application behavior | No |
| Synthetic browser tests | Often stop at DOM ready, JS enabled | No |
| Lighthouse | Runs JS, uses cached assets | No |
| CDN analytics | Hits, bandwidth, response codes | No |
| HTML output validation | Raw size, text, semantic structure | Yes |
| Bot-perspective fetch | What crawlers actually receive | Yes |
A page can drop from 42 KB HTML to 5 KB after a deploy. Every monitoring tool stays green. Rankings collapse within 72 hours.
Guard treats this as a hard failure: HTML <1 KB, visible text <200 chars, script-dominated DOM. That's not a warning. That's broken.
What We See in Production
We see this constantly. Three patterns account for nearly every silent deindexing event.
Hydration failure on deploy
API contract changes overnight. A component throws during mount. React stops rendering the subtree (or the whole tree).
Browser: layout shell renders, content never appears
HTML: ~4 KB, no real text
Result: page deindexed within daysSee the hydration crashes deep dive for the full failure mode.
Build regression (Vite / React)
A config change disables SSR output, removes a plugin, or swaps a build target. The bundle still builds. The output is gutted.
Before deploy
35 KB HTML
2,400 words
After deploy
6 KB HTML
<100 words
No alerts. No errors. Rankings drop in days. This is the most common silent regression we see.
Third-party script blocks render
An auth provider, Stripe, or analytics script fails early in the boot sequence. JS execution halts. The DOM never completes.
GET / 200 OK 4.1 KB
GET https://js.stripe.com/v3/ timeout
// App.tsx never mounts. HTML stays a shell.Guard flags this as script_shell_only, js_crash, or content_drop — because that's exactly what happened.
All three return 200 OK. All three pass every monitor you have. All three quietly turn your homepage into an empty document.
How to Detect It
Stop relying on the browser. Check what bots actually receive.
1. Check the raw HTML
Use curl or View Source (not Inspect — that shows the rendered DOM).
curl -s https://yoursite.com | wc -c
# Healthy: 20,000–120,000
# Broken: 2,000–8,000
curl -s https://yoursite.com | grep -oP '(?<=>)[^<]+' | tr -s ' \n' | wc -c
# Visible text characters
# Healthy: 500+
# Broken: <200You should see paragraphs, headings, and structured content. If you see scripts and an empty div, it's broken.
2. Compare before/after deploy
Snapshot HTML size and text length per page. Diff after every deploy. Two thresholds matter:
- • HTML bytes dropped >50% → high deindexing risk
- • Visible text dropped >40% → likely already deindexing
3. Validate structure
Check the raw HTML for these elements:
- •
<title>present and non-empty - •
<h1>exists - • At least one
<p>with real text - • Internal links present
4. Force failure conditions
Disable JavaScript in DevTools and reload. If the page goes blank, you've confirmed every bot and ~5% of real users are getting nothing.
Real Thresholds
These are the cutoffs we see in production data — not theoretical limits, actual indexing failure points.
| Metric | Healthy | Warning | Broken |
|---|---|---|---|
| HTML size | 20–120 KB | 8–20 KB | <8 KB |
| Visible text length | 1,000+ chars | 200–1,000 chars | <200 chars |
| Word count | 300+ words | 50–300 words | <50 words |
| Internal links | 10+ | 1–9 | 0 |
| H1 present | Yes | — | No |
| Title length | 30–60 chars | 1–29 chars | Missing |
If your homepage is sitting at 5 KB with <200 characters of visible text, Google sees nothing. That's not an opinion — it's the threshold below which indexing reliably fails.
Solutions
Three layers — fix the output, validate it in production, monitor real pages.
1. Fix the output, not the symptoms
- • Return meaningful HTML on the first request
- • Don't depend on hydration for core content
- • Fail your build if content is missing or below baseline
2. Validate HTML in production
Add automated checks for:
- • HTML size relative to a per-page baseline
- • Visible text length
- • Title and H1 presence
If any fail, treat it like a production incident — because it is one.
3. Monitor pages, not infrastructure
Stop measuring whether the server is up. Measure whether the page contains content. Snapshot real pages, diff the output, fail loud when content drops.
DataJelly Guard does exactly this
Guard snapshots real pages and validates content at the HTML layer — visible text length, DOM size changes, title/H1 presence, script-heavy rendering. It catches blank pages, script shells, and content regressions before search traffic drops. Built for React, Vite, and Lovable apps.
Practical Checklist
Run this after every deploy. If any check fails, your page is not indexable — regardless of what your dashboard says.
HTML response > 20 KB on content pages
Single-digit KB is a script shell
Visible text > 200 characters
Measured in raw HTML, not rendered DOM
Title tag present and meaningful
30–60 chars, descriptive
H1 present in raw HTML
Not injected after hydration
Content visible in View Source
Scripts shouldn't dominate the body
No >40% text drop between deploys
Compare raw HTML before/after release
No >50% HTML size drop between deploys
The single strongest regression signal
Page renders with JavaScript disabled
Open DevTools → disable JS → reload
Run These Tests Now
Guard automates all of this. Until it ships, run these manually — no signup required.
Each tool below tests a different layer of the empty-HTML problem. If your site loads but Google sees nothing, these will show you exactly where it breaks.
Page Validator
Check whether your HTML contains the headings, links, and content bots need.
HTTP Debug
Inspect raw HTTP responses by user agent — see what Googlebot actually receives.
Visibility Test
Compare what bots see vs what users see — the core empty-HTML check, done manually.
Page Speed Analyzer
Check Core Web Vitals and rendering performance that uptime tools miss.
Robots.txt Tester
Verify crawlers aren't blocked from the pages you think are live.
The takeaway
A 200 OK response means nothing. If your HTML is empty, your page is invisible — to Google, to ChatGPT, to every crawler that matters.
Modern JavaScript apps fail at the content layer, and most teams don't measure it. That's why traffic drops feel "random." They're not. You shipped an empty page.
FAQ
Interested in Guard?
Guard is launching soon. If your React, Vite, or Lovable app has ever quietly shipped an empty page to production, this is built for you.