DJ
DataJelly
Visibility Test
EdgeGuard
PricingSEO ToolsGuidesGet Started
Dashboard
Back to Blog
Blog
Guard
April 2026

Script Shell Pages: When Your App Loads But Nothing Works

A deploy goes out at 2 PM. At 2:03 PM, your homepage is returning 200 OK with a 4.2 KB HTML payload. No alerts fire. By 6 PM, bounce rate has spiked, conversions are near zero, and Googlebot is fetching pages with no indexable content. The UI looks fine locally. In production, the app loads — and renders nothing.

What a script shell looks like:

200 OK

HTTP status

4.2 KB

HTML size

<100

visible chars

✓

all monitors green

This is the default failure mode of modern SPAs. It passes every system check.

Reading progress0%

On This Page

What's Actually Happening

A script shell page is HTML that contains JavaScript bootstrapping code but no usable content. Every SPA framework ships this by default — Vite, CRA, Lovable, most React setups.

A typical production response looks like this:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Your App</title>
    <link rel="stylesheet" href="/assets/index-9f3a1.css">
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/assets/index-9f3a1.js"></script>
  </body>
</html>

That response is often:

  • • 2–6 KB total
  • • Under 100 characters of visible text
  • • Zero semantic elements (no <h1>, <article>, <nav>)
  • • A single root div with no children

Everything depends on JavaScript executing correctly. There is no fallback. If the bundle 404s, if hydration throws, if the API returns 500 — users get a blank page and bots get an empty document.

Browser vs HTML Reality

The disconnect between what your team sees and what bots see is the entire problem.

What the browser shows

  • • Full UI with navigation
  • • Product data, pricing, testimonials
  • • Working CTAs and forms
  • • ~35 KB rendered DOM, 1,200+ words

What the HTML actually contains

  • • An empty container <div id="root">
  • • Script and stylesheet references
  • • No headings, no paragraphs, no links
  • • ~4 KB total, <100 visible chars

Both are the same page. Both return 200. One is the page you built. The other is what every bot, every crawler, and every user with a failed JS load actually receives.

Why It Looks Healthy

Every infrastructure signal you have will tell you the page is fine. None of them validate content.

Status code200 OK
TTFBFast (<100ms)
CDNServing cached HTML
Backend logsClean
Visible text in HTMLNone
Semantic elementsZero
Content discoverable by botsNo
ConversionsDown sharply

The system is healthy. The page is unusable. This is a page-level failure mode that infrastructure monitoring is structurally incapable of catching.

Why Tools Miss This

Most teams monitor infrastructure, not output. Every standard tool has the same blind spot.

ToolWhat It ChecksCatches Empty HTML?
Uptime monitoringConfirms 200 OK, ignores body No
Server logsBackend behavior only No
Synthetic testsOften stop at DOM ready No
LighthouseRuns with JS enabled and cached assets No
Error trackingThrown JS exceptions No
HTML output validationRaw HTML size, content, structure Yes
Bot-perspective fetchWhat crawlers actually receive Yes

Your system can be 100% healthy by every standard metric while every page is unusable. None of these tools answer the question that actually matters: "Does this page contain content?"

What We See in Production

We see this constantly, and it's almost always tied to deploys. Three patterns account for nearly every case.

1

Missing JS bundle (most common)

A new build references /assets/index-9f3a1.js. The CDN still serves old assets at the edge. The file returns 404.

Result: HTML loads (4 KB), script fails to load, page never renders. Users see a blank screen. Bots see nothing. Revenue stops immediately.

GET /                         200 OK   4.2 KB
GET /assets/index-9f3a1.js    404 Not Found
// Page never mounts. No error in your logs.
2

API-first rendering failure

The app waits for /api/page-data before rendering anything. The API returns 500 for ~5% of requests due to a downstream timeout.

Result: HTML loads, JS runs but never mounts content, page stays empty. This shows up as intermittent "ghost outages" — some users see content, others don't. Support gets reports you can't reproduce.

3

Hydration crash after deploy

Server and client output diverge. React throws during hydration with "Text content does not match server-rendered HTML." Rendering halts.

Result: Partial UI or full blank, no recovery, still returns 200. See our companion post on hydration crashes for the full breakdown.

All three ship to production without alerts. All three return 200 OK. All three turn your site into a 4 KB empty response.

How to Detect It

Stop guessing. Check the output directly.

1. Fetch raw HTML

Pull the page without executing JS. If your homepage HTML is 3–5 KB with no readable text, it's broken.

curl -s https://yoursite.com | wc -c
# Under 5KB → script shell

curl -s https://yoursite.com | grep -oP '(?<=>)[^<]+' | wc -w
# Under 100 words → bots see nothing

You should see headings, paragraphs, and links in that output. If you don't, bots won't either.

2. Compare source vs rendered

Open the page in a browser and copy a chunk of visible text. Then view source and search for it. If it's missing, your content is JS-only.

This is the simplest test that exists for content delivery, and almost no team runs it after every deploy.

3. Check HTML structure

Red flags in the raw HTML:

  • • <body> contains only one <div>
  • • No <h1>, <article>, or <main>
  • • No meaningful text nodes
  • • All content references resolve via JS at runtime

4. Force failure conditions

Block JS in DevTools or simulate a failed script load. If the page becomes blank, you've confirmed the dependency. Now you know what 5% of your users (and 100% of your bots) are seeing.

Solutions

There's no single fix. The problem spans rendering strategy, monitoring, and deploy hygiene.

Put content in the HTML

If your content only exists after JS runs, it is fragile by design. At minimum:

  • • Core text content must exist in the HTML response
  • • Navigation links must be present
  • • Page structure (headings, semantic tags) must be complete

This is what DataJelly Edge does for SPAs that can't migrate to SSR — it generates real HTML for bots without rewriting the app.

Validate HTML, not behavior

Stop relying on "it works in the browser." Validate:

  • • HTML size (content pages should not be single-digit KB)
  • • Text presence (raw, not rendered)
  • • Structural elements (h1, main, nav, links)

Monitor real pages

You need checks that fail when content disappears. Not "is the server up?" but:

  • • "Does this page contain 500+ words of text?"
  • • "Does the <h1> exist?"
  • • "Did HTML size drop from 35 KB to 4 KB between deploys?"

That's the difference between catching a script shell regression and shipping it.

DataJelly Guard does exactly this

Guard inspects real HTML output, flags content loss, and catches script shell regressions before they hit users. Built for React, Vite, and Lovable apps where this failure mode is the default.

Practical Checklist

Run this after every deploy. If any of these fail, investigate immediately — regardless of what your status dashboard says.

HTML response > 15 KB for content pages

Single-digit KB is a script shell

Visible text present in raw HTML

Not just JS-injected — actually in the response body

h1, main, and links exist in source

Bots index structure, not your rendered DOM

No dependency on API calls for initial render

If the API hiccups, the page should still show content

JS bundles return 200, not 404

Verify all asset hashes after deploy

Page still shows content with JS disabled

Open DevTools, disable JS, reload. What do you see?

No sudden HTML size drops between deploys

40 KB → 4 KB means something broke

Hydration completes without console warnings

Even one warning can kill an entire subtree

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 script shell problem. If your page returns 200 but the HTML is empty, 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 script shell 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

Script shell pages are not rare bugs. They are the default failure mode of SPAs. A single missing script or failed API turns your site into a 4 KB empty response that still returns 200 OK.

Your monitoring will say everything is fine. Your users and search traffic will say otherwise. If you're not validating HTML output directly, you are shipping blind.

Interested in Guard?

Guard is launching soon. If your React, Vite, or Lovable app has ever shipped a 4 KB shell to production without anyone noticing, we built this for you.

Ask a QuestionLearn About Guard

FAQ

Related Reading

DataJelly Guard

Rendering monitoring for React, Vite, and Lovable apps

Hydration Crashes: The Silent Killer

Companion Guard post on dead-button failures

Why Your React App Shows a Blank Page in Production

How blank-page failures happen and why monitoring misses them

Your Site Returns 200 OK — But Is Completely Broken

When status codes lie about page health

Your HTML Is Only 4KB

Why tiny HTML responses mean your content is invisible

Page Validator

Check bot-readiness of any URL

HTTP Debug Tool

Inspect raw HTTP responses by user agent

Visibility Test

See what bots see on your pages

Reading progress0%

On This Page

DataJelly

SEO snapshots for modern SPAs. Making JavaScript applications search engine friendly with enterprise-grade reliability.

Product

  • DataJelly Edge
  • DataJelly Guard
  • Pricing
  • SEO Tools
  • Visibility Test
  • Dashboard

Resources

  • Blog
  • Guides
  • Getting Started
  • Prerendering
  • SPA SEO Guide

Company

  • About Us
  • Contact
  • Terms of Service
  • Privacy Policy

© 2026 DataJelly. All rights reserved. Built with love for the modern web.