Google renders JavaScript, but rendering is a deferred second pass
Yes, Google can read JavaScript sites. Googlebot uses a current version of headless Chromium, executes your scripts, and indexes what the page produces. So the old warning that "Google can't see JS content" is out of date. The real issue with JavaScript SEO is timing, not capability: rendering is a second, deferred pass, not part of the first crawl. Anything that only appears after client-side JavaScript runs gets pushed into a render queue that can lag, and if that render fails or stalls, Google indexes an empty shell. So the practical rule holds: put your critical content and links in the initial HTML, not because Google is incapable, but so it never has to wait or gamble on your scripts running cleanly.
This piece is a spoke of our technical SEO guide, and it stays narrowly on how Google handles JavaScript and what you should do about it.
How Google renders JavaScript, step by step
Google's own JavaScript SEO basics documentation describes three distinct phases, and the gap between them is the whole story.
- Crawl. Googlebot fetches the URL, checks robots.txt for permission, and parses the raw HTML it receives. At this stage it only sees links written as real anchor tags in the response, and it queues new URLs it discovers.
- Render. Every page that returns an HTTP 200 goes into a rendering queue. When resources free up, headless Chromium loads the page, runs the JavaScript, and builds the final DOM. Google's guidance says the page "may stay on this queue for a few seconds, but it can take longer than that."
- Index. Google parses the rendered HTML a second time, extracts any links and content that only existed after JavaScript ran, and adds them to the index.
The load-bearing detail is that link discovery and content extraction happen twice, in two separate passes, with an unpredictable delay between them. If your navigation and body copy are in the raw HTML, they get processed in pass one immediately. If they only exist after hydration, they wait in the render queue.
The render queue is the real risk
The render queue is a backlog of pages waiting for Googlebot's rendering resources. Google doesn't publish a fixed wait time. For a small site with fresh, popular content the delay may be seconds; for a large or low-priority site it can stretch much longer, which is a genuine problem for time-sensitive pages like product launches, news, or a store's stock status.
Two failure modes make this worse than a simple delay:
- Render failure. If a script throws, a bundle is blocked by robots.txt, or an API call times out, the render produces incomplete HTML and Google indexes whatever partial state it got. Client-side rendering that fails silently is invisible until you check the rendered DOM.
- Stale links. New URLs are mostly discovered from anchor tags in the first pass. If your internal links only render client-side, the crawling and indexing of deeper pages slows down because Google finds them later, in the render pass, rather than immediately.
Server-side rendering (SSR) and static site generation (SSG) sidestep both by putting the finished HTML in the initial response. Google confirms this: "server-side or pre-rendering is still a great idea because it makes your website faster for users and crawlers, and not all bots can run JavaScript."
Client-side vs server-side rendering for SEO
The difference between these two comes down to where the HTML is assembled. It is the single biggest lever in JavaScript SEO.
| Approach | Where HTML is built | What Google sees on first crawl | SEO risk |
|---|---|---|---|
| Client-side rendering (CSR) | In the browser, after JS runs | Near-empty shell | High — depends on render queue and script success |
| Server-side rendering (SSR) | On the server, per request | Full content and links | Low |
| Static site generation (SSG) | At build time, cached | Full content and links | Lowest |
| Hydration (SSR/SSG + client JS) | Server first, JS enhances after | Full content and links | Low — recommended default |
Hydration is the pattern Google now points to: render real HTML on the server or at build time, then attach JavaScript in the browser to make it interactive. Frameworks like Next.js, Nuxt, Astro, and SvelteKit do this by default. The web.dev guide on rendering on the web walks through the full spectrum and the performance tradeoffs of each, including hydration's own catch: a page can look loaded but not respond to input until its client scripts execute. Getting this right also helps your Core Web Vitals, since server-rendered HTML paints content sooner, and it feeds into broader page speed work.
Dynamic rendering is deprecated, so don't build on it
Dynamic rendering meant detecting crawlers and serving them a pre-rendered version while users got the JavaScript app. Google no longer recommends it. Their dynamic rendering documentation now states plainly: "Dynamic rendering was a workaround and not a long-term solution for problems with JavaScript-generated content in search engines." It "creates additional complexities and resource requirements."
The recommended replacements are the same three from the table: server-side rendering, static rendering, and hydration. If you inherited a setup using Rendertron or a prerender service purely for bots, plan a migration to SSR or SSG. Serving crawlers different content than users is also fragile, because it can drift into cloaking territory if the two versions diverge.
Is React bad for SEO?
No. React, Vue, Angular, and Svelte are all fine for SEO as long as you render meaningful HTML on the server or at build time. A default single-page app ships an almost empty HTML file and builds everything client-side, which is the setup that runs into render-queue problems. The fix is not to abandon the framework; it is to use its server-rendering mode. React with Next.js, Vue with Nuxt, and so on all produce crawlable HTML out of the box. The framework is neutral. The rendering strategy decides your outcome.
How to debug JavaScript SEO problems
You don't have to guess whether Google sees your content. Here is the exact flow I use.
- Compare view-source with the rendered DOM. View-source shows the raw HTML Google gets in the crawl pass. Open DevTools and inspect the live DOM to see the post-JavaScript version. If your headline, product description, or links appear only in DevTools and not in view-source, they depend on the render queue.
- Use the URL Inspection tool in Search Console. It shows the actual rendered HTML and a screenshot of how Googlebot rendered the page, plus any resources it couldn't load. This is the ground truth, not a simulation. If you haven't connected your property yet, our Search Console integration surfaces these signals alongside the rest of your data.
- Check that links are real anchor tags. A link written as an onClick handler with a router push is invisible to the crawl pass, because Google can't follow a JavaScript event as a link. Every internal link that matters for crawling should be a proper anchor tag with a real href. This one issue silently strangles internal link equity on a lot of SPAs.
- Confirm your JS files aren't blocked. If robots.txt disallows your script or CSS bundles, Chromium can't render the page. Google's guide to fixing JavaScript search problems covers this and other common failures.
- Run a crawl that renders JavaScript. A site audit that executes JS flags pages where rendered content and raw HTML diverge, so you catch render-dependent content at scale instead of spot-checking. Our site audit tool does exactly this.
Once the rendering is sound, the rest of the technical layer applies normally: canonical tags to consolidate duplicates, XML sitemaps to surface URLs, schema markup for rich results, and a full technical SEO audit to catch what a single check misses.
The practical takeaway
Treat "Google renders JavaScript" as true but conditional. It renders on a delay, in a separate pass, and only if your scripts and resources cooperate. Put your critical content and links in the HTML the server sends. Use SSR, SSG, or hydration instead of pure client-side rendering. Write real anchor tags. Verify with URL Inspection rather than assuming. Do that, and JavaScript stops being an SEO liability and becomes a non-issue.