Guides/JavaScript SEO: How Google Renders JS Pages (and Where It Breaks)
Guide

JavaScript SEO: How Google Renders and Indexes JS-Heavy Pages

A technical guide to JavaScript SEO: how Google's crawl-render-index pipeline handles JS, the failure modes it introduces, and how to serve indexable content.

Google handles JavaScript in a three-stage pipeline — crawl, render, index — and each stage can silently drop content the previous one never saw. The crawler reads only your raw HTML; rendering happens later, on a separate queue, in a headless Chromium that has hard limits. Only the first 15 MB of any resource is fetched. If your content or links appear only after JS runs, they enter that gauntlet, and some of them do not survive it.

The crawl-render-index pipeline

Understanding JavaScript SEO starts with the order of operations. Googlebot fetches a URL and parses the raw HTML first. It queues every <a href> it finds and, if the response is HTTP 200, passes the page forward. Nothing that requires JavaScript exists at this point.

The page is then queued for the Web Rendering Service (WRS), an evergreen headless Chromium. WRS executes your JavaScript, the DOM mutates, and a rendered HTML snapshot is produced. That snapshot is what gets indexed — and any links discovered during rendering feed back into the crawl queue for the next pass. The render queue delay is usually short, but it is not guaranteed. On a large or frequently changing site, that lag interacts with your crawl budget: pages waiting to render are pages not yet indexed.

The practical takeaway: raw HTML and rendered HTML are two different documents, and Google acts on both. Crawlinx exists partly to show you the gap between them.

What Googlebot will not do

WRS is a real browser, but it is not a user. Several behaviors that work fine for humans are invisible to Google.

It does not click. Googlebot executes JavaScript but never triggers user-action events. Content behind an onclick handler, a tab that loads on interaction, or a "load more" button is not seen.

It does not scroll. All primary content must be present when the page loads or when it enters the viewport — do not defer it behind a scroll event. Native loading="lazy" and IntersectionObserver are fine; a scroll listener that fetches your article body is not.

State does not persist. WRS is wiped between page loads. localStorage, sessionStorage, and cookies do not carry across navigations. Never route or gate content on them.

Not every API exists. WebGL, WebSockets, WebRTC, and camera access are not guaranteed. Feature-detect and provide a fallback that still renders your content.

SSR vs CSR: pick a rendering strategy

Pure client-side rendering (CSR) ships an empty shell and builds the page in the browser. It works, but it puts everything on WRS and the render queue, and it leaves nothing for crawlers with weaker JS support. Bing renders JS far less reliably than Google — do not assume BingBot runs your SPA. Server-rendered HTML matters more, not less, for Bing.

Prefer one of these:

Dynamic rendering — serving a prerendered version to bots only — is deprecated. Google calls it "a workaround, not a long-term solution." Do not build new architecture on it.

Routing, titles, and metadata

Routing must use the History API (pushState) with real, crawlable <a href> URLs. Hash fragments (#/products) are dead — the old AJAX-crawling scheme is gone, and Google will not treat them as separate pages. Links written as href="#" with an onclick handler are invisible, which is a direct hit to your internal linking.

Every route needs a unique <title> and meta description. JavaScript can set document.title, and WRS captures the result — but a title that changes between raw and rendered HTML is a signal worth auditing, because Google may act on either version.

Common JavaScript SEO failure modes

One more thing: client-side analytics undercount Googlebot. Do not use them to judge crawlability. Use Search Console Crawl Stats and URL Inspection — the Rendered HTML view confirms exactly what Google produced.

How Crawlinx helps

Crawlinx fetches both the raw HTML and the rendered DOM, then diffs them — its core differentiator for JavaScript SEO. The render-diff checks flag:

Related structural checks cover the surrounding failure modes: blocked JS/CSS or pages, noindex present in the raw HTML, and a missing canonical.

Takeaway

JavaScript is not a ranking problem; it is a delivery problem. Google's crawler reads raw HTML, renders on a delayed queue with real limits, and indexes what survives — while Bing may not render at all. Serve crawlable HTML through SSR or static rendering, keep routing and metadata in real markup, and diff raw against rendered to catch what only your users can see.

Related
render.content_js_only render.links_js_only render.title_changed render.canonical_changed render.robots_changed rendering.js_dependent robots.blocked index.noindex canonical.missing

Audit your own site — free

77 checks, internal PageRank, render-diff. No signup, results in ~30s.

Scan your site →