crawlfix.ai
Sign inRun free scan
All posts
JS SEOApr 22, 2026 · 6 min read

The hidden gap between your raw HTML and what Google sees

Most SEO crawlers fetch your page once, before JavaScript runs. Modern users see something completely different. The delta is where ranking gets quietly destroyed.

By Crawlfix Labs

There is a quiet category of SEO bug that does not show up in most audits, because most audits never look for it. The page returns 200, the title tag is set, the meta description exists. The crawler is happy. The user, on the other hand, sees a fully populated app a half-second later. So does Google, eventually, on a separate render queue. Your competitors do not have this gap, and that shows up in rankings before it shows up in any tool.

We built Crawlfix to surface that gap directly. Every scan does two fetches of the same URL. The first is a raw HTTP request with no JavaScript, exactly what a fast first-pass crawler sees. The second is a real Chromium render that waits for hydration. Then we diff the two.

Why "view source" lies to you

If you ship a single-page app without server rendering, here is what happens in production. Your origin returns a small shell: a div with id root, a few script tags, maybe a loading spinner. The HTML is technically valid. The bundle then hydrates and paints the actual content client-side.

The first crawler pass sees the shell. Whether your content ever gets indexed depends on whether the second-pass render queue gets to your page, succeeds without errors, and trusts the result enough to include it. That second pass is not free for Google, it is delayed, and it is not guaranteed.

Two pages on the same site can have wildly different outcomes. A heavily linked landing page tends to get rendered. An interior product page that hydrates 800ms in, after a deferred bundle, often does not.

What the diff exposes

When you compare raw HTML against the rendered DOM, a small handful of patterns repeat over and over:

  • Empty body before hydration. Word count of 5 raw, 1,800 rendered. The page is invisible to anything that does not render.
  • Title swapped client-side. Raw <title> says App. Rendered <title> says the actual page topic. Search snippets get the wrong one for weeks.
  • Links injected by JS. Internal navigation only exists after the router mounts. Crawl depth from your home page collapses to 1.
  • Schema markup missing from raw, present after render. JSON-LD that your CMS injects via a client effect. Rich result eligibility evaporates.
  • Canonical tag set client-side. Duplicate content signals fire before the canonical resolves.
Pattern

The shapes of these bugs are boring. The cost is not. A title-tag swap on a high-traffic landing page is the difference between ranking for your brand and ranking for the literal string "App."

What a normal crawler reports vs. what is happening

Run a typical audit on a hydrated React app and you tend to get a polite, mostly-green report. "Title tag present. Meta description present. H1 present." All true at the moment of the snapshot. None of it true at the moment Google's first-pass indexer arrives.

The thing the audit cannot tell you is whether the title tag was already there, or whether it appeared 600ms after fetch. That is the only question that matters for indexability.

Before JS
<title>App</title> <meta name="description" content="" /> <div id="root"></div>
After hydration
<title>Pricing for teams scaling on Next.js</title> <meta name="description" content="Plans that grow with..." /> <main>...3,200 words of content...</main>

The before column is what the crawler indexed. The after column is what your customer sees. Pick one.

What to do about it

Three moves, in priority order.

  1. Server-render or pre-render the routes that matter. Marketing pages, product pages, blog. Anything you would link from a paid ad. SSR or static export removes the gap entirely for those routes.
  2. Audit the gap on the rest. For routes you cannot easily SSR, scan them and decide which ones can safely stay client-rendered. A logged-in dashboard is fine. A help article is not.
  3. Watch for regressions. Hydration drift is the kind of bug that creeps in silently when someone moves a <title> into a useEffect to fix a flash. Treat the rendered-vs-raw diff as a permanent test, not a one-time audit.

If you want a starting point, point Crawlfix at any URL on your site and you will get the diff in about thirty seconds. The free preview shows the score, the framework, and the top issues. That is enough to know whether you have this problem.


Want a free scan of your own site? It runs in your browser and takes about 30 seconds.
Run free scan