_**JavaScript SEO**_ still carries a stubborn piece of received wisdom: Google supposedly processes pages in "two waves of indexing", with days or weeks between reading the HTML and executing the JavaScript. That model, presented by Google in 2018, no longer appears in its documentation. Rendering now works as an asynchronous queue, and the documentation says a page usually waits there a few seconds, sometimes longer. The useful question is therefore no longer when Google will execute your JavaScript, but what it actually kept once rendering was done. That information exists: Search Console's URL Inspection tool and its Page indexing report record, for every URL, the verdict issued after the JavaScript ran. Two questions organize the diagnostic: which statuses point to failed rendering, and how to check what Google indexed without trusting your own crawler's render.

## How Google Processes JavaScript Today

Google processes JavaScript pages in three phases: crawling, rendering, and indexing. Googlebot first reads the HTML your server returns, then places the page in a rendering queue; a headless Chromium executes the JavaScript, and indexing operates on the result of that render.

Two points from the current documentation correct widespread beliefs. First, the wait in the render queue is usually measured in seconds. The multi-day delays between a "first wave" and a "second wave" belong to a model Google no longer uses in its documentation, and the often-cited "5-second execution limit" doesn't appear there either. Second, rendering is still not guaranteed: it depends on Google's resources, and some instructions short-circuit it. The documentation states, for example, that when Google encounters a noindex tag it may skip rendering entirely.

Google's renderer also plays by its own rules, different from a browser's. It declines permission requests, doesn't open WebSocket or WebRTC connections, and keeps no state between page loads: Local Storage and Session Storage data are cleared across page loads. Content that depends on a cookie, a session or a user interaction is therefore very likely to never appear in the rendered version.

## Your Crawler's Render Is Not Google's Verdict

To check a JavaScript page, the common reflex is to run a crawler in rendering mode and compare the initial HTML with the rendered DOM. That comparison is useful, but it has a structural limit: it shows what your tool rendered, with its engine, its delays and its settings. It doesn't tell you what Google rendered, and above all it doesn't tell you what Google decided to index.

The two results can diverge for ordinary reasons: a script blocked for Googlebot but reachable by your crawler, a network call that times out on Google's side, a resource cached in an old version, content conditioned on state Google's renderer wipes, or simply a partial execution. A page can look complete in your audit and be indexed incomplete by Google, with no error showing anywhere.

The source that settles it exists: the official verdict. Search Console's [URL Inspection](/content/en/blog/url-inspection-tool/index.html) shows the HTML rendered by Google itself, the resources it loaded, and the JavaScript exceptions it hit. And the Page indexing report records the final decision, URL by URL. In other words, to know whether your JavaScript is hurting your SEO, polishing your own render isn't enough: you have to read what Google concluded from its own.

## The Grid: Rendering Symptom, Status, Cause, Fix

Every rendering failure leaves a recognizable footprint in the indexing report. The table summarizes the most frequent matches on JavaScript-heavy sites.

| Symptom | Most frequent status | Likely cause |
| --- | --- | --- |
| The initial HTML is a shell, content comes from JS | "Crawled - currently not indexed", or page indexed empty | Incomplete render, or judged low-value |
| Client-side routing, URLs that render an empty state | "Soft 404" | No real error code, "not found" page served as 200 |
| Large site, heavy JS, recent pages waiting | "Discovered - currently not indexed" | Render queue and crawl budget |
| Tags injected or changed via JS (canonical, title, robots) | Duplicate/canonical statuses | Conflicting directives between initial HTML and render |
| Injected content, lazy loading, broken hydration | Case by case: crawled without the content, duplicates | The content doesn't exist in the rendered version |

### The CSR Shell: Rendered, Read, Set Aside

On a client-side rendered page, the initial HTML contains almost nothing; everything arrives with the JavaScript. When rendering succeeds and the content convinces, the page indexes normally. When rendering fails or the result looks thin, two verdicts come up most often: ["Crawled - currently not indexed"](/content/en/blog/crawled-currently-not-indexed/index.html), when Google read the rendered page and didn't keep it, and the more misleading case of the page [indexed without content](/content/en/blog/indexed-without-content/index.html), when Google indexes the empty rendered shell.

### Client-Side Routing and Empty States: "Soft 404"

In an application with JavaScript routing, a non-existent URL doesn't return a 404: the server answers 200 and the JavaScript displays "no results". Google recognizes that pattern and files these pages under ["Soft 404"](/content/en/blog/soft-404/index.html). Its documentation devotes a whole section to avoiding it with client-side rendering.

### Heavy JavaScript on Large Sites: The Wait That Stretches

Rendering consumes resources. On a large site where every page requires a full JavaScript execution, crawling and rendering slow down, and recent pages pile up in ["Discovered - currently not indexed"](/content/en/blog/discovered-currently-not-indexed/index.html).

### Tags Injected via JavaScript: Diverging Directives

A title, a canonical or a robots tag that only exists in the rendered version creates an ambiguous situation: the initial HTML says one thing, the rendered DOM says another. The safest rule is to keep indexing directives (canonical, robots, title) in the initial HTML rather than in JavaScript.

### The Pitfalls Beyond SPAs: Injected Content, Lazy Loading, Hydration

This subject isn't limited to single-page applications. A classic site can inject entire blocks via JavaScript: customer reviews, product specs, FAQs, recommended content. If the script fails on Google's side, the page gets indexed without those blocks, and nothing flags it.

## The SPA Case

A single-page application concentrates these pitfalls in their most acute form: all content depends on rendering, routing is fully client-side, and failure produces no visible error. That case has its own article, with the four statuses that betray a poorly indexed SPA.

## Diagnosing at Scale: Google's Verdicts on Your JavaScript-Heavy URLs

URL Inspection shows Google's render for one page. It's the tool of proof. On a site where thousands of pages depend on JavaScript, the question isn't "is this URL rendered correctly?" but "what share of my JavaScript-heavy pages is actually indexed, and with which exclusion reasons?".

With segmentation by rendering type, the reading becomes direct: do the JavaScript-heavy segments concentrate the rendering-failure statuses, or do they behave like the HTML-served pages? A clear gap between the two families points at rendering as the cause.

## Verifying After the Fix: Rendering Is Asynchronous

Fixing a rendering problem doesn't change the indexing report immediately. Google has to revisit each URL, re-render it and re-decide. Verification therefore requires a dated follow-up: rerun the same analysis on the same URL list a few weeks after the deployment, and compare.

The complete loop: understand what Google does with your JavaScript, read the verdicts it issued after its render, fix what they point at, then confirm the shift over time.
