How Google Crawls JavaScript
A page that looks complete in your browser can reach Google as a near-empty shell. The reason is timing: your content arrives after JavaScript runs, but a crawler first sees only the HTML the server sent. Whether your words ever get indexed depends on a second step, rendering, that you do not control and cannot take for granted.
This guide walks the path a JavaScript page takes through Google, from the first fetch to the index, and shows where it breaks. It is the first stage of the wider JavaScript SEO cluster and pairs with the SEO for single page apps overview.
What you'll learn
The crawl, render, index pipeline
For a static page, crawling and indexing are nearly the same moment. For a JavaScript page, a third step wedges in between. Googlebot fetches the HTML, sets the page aside to be rendered, runs the scripts in a browser engine, and only then indexes whatever the render produced.
Why rendering is its own stage
Rendering is expensive, far more so than fetching text, so Google does not do it inline with the crawl. That single fact explains most JavaScript SEO trouble: anything that depends on the render is at the mercy of a later, separate, resource-limited step rather than guaranteed the instant your page is crawled.
What Googlebot can and cannot do
The renderer is a real, modern, Chromium-based browser, so it executes your JavaScript and builds the same DOM a visitor would see. What it does not do is behave like an engaged human poking at the page.
No clicks, no scroll, no stored state
Googlebot does not click buttons, fill forms, scroll to trigger lazy content, accept cookie prompts, or carry login state between pages. It also discards local storage and similar state between loads. So content that appears only after one of those actions is, to Google, content that does not appear at all. Anything important must be reachable without interaction.
The render queue and deferred rendering
Because rendering is batched, a crawled page waits in a queue before its scripts run. That delay is usually short, but it is real, and on a large or slow site it compounds.
Content behind JavaScript can be indexed late
While a page sits in the render queue, the only thing Google has is the raw HTML from the crawl. If that HTML is an empty shell, the page can be indexed thin, or with nothing, until the render catches up. For pages where freshness or completeness matters, that lag is a reason to put the important content into the initial HTML through server-side rendering or prerendering.
Never block JavaScript and CSS
To render a page, Googlebot has to download the same scripts and styles the browser does. Block those files and you hand the renderer a broken page.
Let crawlers fetch your resources
# Bad: blocks the JavaScript Googlebot needs to render
Disallow: /assets/js/
# Good: let crawlers fetch the JavaScript and CSS
Allow: /assets/
A surprising number of indexing problems trace back to a well-meaning Disallow that starves the renderer. Keep your bundles and stylesheets crawlable, and confirm it; the same URL Inspection tool below flags resources that Google could not load.
Use real links and server-visible content
Google discovers pages by following links, and it only follows the kind it can see. A real anchor with an href is a link; an element that navigates through a click handler is not.
Real anchors beat JavaScript navigation
<!-- Crawlable: Googlebot follows this -->
<a href="/products/42">Product 42</a>
<!-- Not crawlable: there is no URL to follow -->
<div onclick="go('/products/42')">Product 42</div>
Route your single page app with real paths and real anchors, the approach from the routing guide using pushState, so every view has a URL a crawler can reach. Then make sure the server returns meaningful content for those URLs rather than an empty container.
Verify what Google actually renders
You never have to guess what Googlebot sees, because Google will show you. The rendered HTML it produces is available for any URL on a property you own.
Checking the rendered HTML in Search Console
Open URL Inspection in Google Search Console, run Test Live URL, and view the rendered HTML and the screenshot. Compare that against the content you expect to rank for. If a heading, a product, or a block of text is missing from the rendered output, it is almost certainly missing from the index, and now you know exactly which step to fix.
That is how Google crawls JavaScript: fetch, queue, render, index, with every stage a place a page can fall short. Keep resources crawlable, content reachable without interaction, links real, and verify the render, and a JavaScript site competes on even ground. Next in the cluster, rendering and indexing looks at exactly what survives that render and when.
Frequently Asked Questions
Does Googlebot execute JavaScript?
Yes. Googlebot renders pages with an evergreen, Chromium-based engine that runs JavaScript, so client-rendered content can be seen. It comes with limits and the render can be deferred, so it is not the same as instant indexing.
Why is my JavaScript content not getting indexed?
Common causes are blocked scripts or CSS in robots.txt, content that only appears after a click or scroll, a render that was deferred or timed out, or navigation that uses JavaScript instead of real links. Confirm the cause with URL Inspection.
Does Google use two waves of indexing?
The old two-waves description is a simplification. Rendering is now closer to continuous, but it can still trail crawling, so treat important content as needing to be present without relying on a later render, using server-side rendering or prerendering.
How do I check what Googlebot sees?
Use URL Inspection in Google Search Console and view the rendered HTML, or run Test Live URL. Compare that rendered output with the content you expect; anything missing there is likely missing from the index too.
Read next: JavaScript Rendering and Indexing, the next guide, or the SEO for single page apps overview.
Building the app you want indexed?
Crawlable routes start in the frontend. See how a single page app is structured in the complete Backbone guide.
Explore the Backbone Guide →