A URL gets fetched at 9:00 and shows up in search that afternoon. An identical-looking URL on the same site gets fetched at the same time and is still missing from the index a day later. Nothing about the two pages looks different in a browser. What separates them is which stage of Google’s pipeline each one cleared, because crawling and indexing are not the same event, and the gap between them is where the URL’s fate is actually decided.
Googlebot fetches URLs. The indexing system decides what to keep. The rendering pipeline handles pages whose content depends on JavaScript. The serving layer picks which stored version answers a given query. Each stage runs on its own signals and its own timing, and a URL can pass one stage while quietly failing the next. The “two-wave” model is the name for one slice of that pipeline, and it is still useful shorthand as long as the current mechanics behind it are understood rather than the 2018-era version most write-ups still repeat.
This guide maps the pipeline stage by stage, names where URLs commonly stall, corrects the stale “rendering takes weeks” claim against current data, and lists what a site owner can actually influence. It treats JavaScript rendering as the single deep topic; crawl scheduling and budget are named where relevant but belong to their own subject.
The five stages a URL passes through #
The pipeline has five distinct stages, and each one produces a decision that determines whether the next stage even runs.
| Stage | What happens | Decision produced |
|---|---|---|
| Discovery | Google learns the URL exists through a sitemap, link, redirect, or manual submission | Added to the crawl queue, or ignored |
| Crawl | Googlebot fetches the URL and processes the HTML response | Content extracted, or crawl failed (404, 500, robots.txt block) |
| Rendering | The Web Rendering Service executes JavaScript and produces the rendered DOM | Rendered content available, or rendering failed or timed out |
| Indexing | Google decides whether the content is worth storing | URL indexed, or excluded as low quality, duplicate, or noindex |
| Serving | Google selects which stored URLs answer a given query | URL surfaces for relevant queries, or is not selected |
Latency differs at every stage. Discovery can finish in seconds. Serving runs on every query in real time. The stages in between vary widely: for most sites the crawl-to-index path completes in seconds to hours, while a long tail of low-authority or heavily JavaScript-dependent URLs waits far longer. That variance, not an average, is what a diagnostic has to account for.
Where the “two waves” framing came from #
Google’s Martin Splitt described the rendering pipeline at Google I/O 2018 as two waves. The first wave: Googlebot fetches the URL, parses the HTML response, indexes the content already present in that HTML, and adds the links it finds to the crawl queue. The second wave: URLs that need JavaScript execution to show their content go to a render queue, the Web Rendering Service processes them, and the additional content is indexed afterward.
The framing produced a durable and correct intuition. Content sitting in the HTML response gets picked up faster than content a browser has to build with JavaScript, and sites that depend on JavaScript for their primary content pay a latency cost for it. That part still holds.
What has not held is the “two separate waves” mental model itself. By 2019 Splitt was already describing the two waves as playing “less and less of a role” and expected crawling, rendering, and indexing to converge over time. The pipeline now behaves less like two discrete passes and more like a single continuous queue: fetch, queue for rendering, render when capacity allows, index the result. The title of this discussion survives as familiar shorthand; the underlying system it describes has moved on.
Google renders nearly everything, and the median is fast #
The most important correction to the old model is scope. Rendering is no longer reserved for pages Google suspects are JavaScript-heavy. Vercel’s 2024 analysis of Googlebot behavior on nextjs.org found that across the fetches studied, effectively all indexable HTML pages were fully rendered, including static pages with no meaningful JavaScript. Rendering is cheap enough that Google runs almost every page through it rather than deciding in advance who needs it.
The timing correction matters just as much. The claim that JavaScript content waits weeks to be rendered is stale. Splitt put the median render delay at roughly five seconds at Chrome Dev Summit 2019. Vercel’s 2024 data on nextjs.org put the 25th percentile near four seconds and the median around ten seconds, with the 75th percentile in the tens of seconds. The delay only stretches into hours at the high percentiles, and into much longer waits only for a thin tail of infrequently crawled, low-priority URLs. For most sites, rendering is a matter of seconds to minutes, not days.
The tail is still real, and it is still where SEO problems live. A low-authority site with heavy JavaScript dependencies can land in the long tail and wait far longer than the median suggests, and it will not be told it is waiting. The honest framing is that the median is comfortable and the variance is the risk, rather than the outdated blanket warning that rendering is slow.
What can fail during rendering #
Five failure modes recur, and each produces a different symptom.
- The render times out. The Web Rendering Service enforces a time budget. Content that has not loaded by the cutoff does not reach the index, so a page that spends several seconds building itself risks having part of its content silently dropped.
- A JavaScript error halts execution. An uncaught exception, an infinite loop, or a blocked async call stops rendering where it is. The page is indexed in whatever partial state it reached.
- Required resources are blocked. JavaScript files, CSS, or API endpoints disallowed in robots.txt cannot be fetched during rendering, so the page renders degraded, missing whatever those resources would have supplied.
- Hydration changes the content. When client-side JavaScript rewrites the DOM after the initial paint, the DOM Google captures can differ from what a user eventually sees, and Google indexes its version.
- Lazy-loaded content never triggers. Content that loads only on scroll, click, or viewport intersection may not load during rendering. It exists in the codebase but never reaches the indexing stage.
Different pages built from the same template can have very different indexation outcomes for these reasons, which is why “the template is fine” is not evidence that a specific URL rendered correctly.
How the indexing stage decides #
Once rendering completes, the indexing stage evaluates the captured content, and its decisions are less visible in Search Console than the earlier stages. Duplicate detection tends to keep one version when a URL is substantially similar to another; the canonical tag is a signal Google weighs but does not have to obey. Quality evaluation excludes pages judged thin or low value regardless of a clean crawl. A noindex directive is respected only if it is visible to the pipeline, so a noindex injected by JavaScript before the DOM is captured is honored while one injected after may not be. Soft-404 detection treats a 200-status page whose content signals “no results” or “not found” as missing, so it stays crawled but unindexed.
Those decisions produce the familiar Search Console states: “Indexed,” “Crawled – currently not indexed,” and the various “Excluded” reasons. Each label reflects a specific decision made at this stage rather than a single generic verdict.
How to diagnose where a URL is stuck #
The diagnostic work starts with comparing the raw HTML response against the rendered DOM. The URL Inspection tool in Search Console and the Rich Results Test both show what Google captured after rendering; comparing that to the source HTML reveals exactly what depends on JavaScript and whether rendering produced the expected result. A faster local version of the same test is opening the page in the browser with JavaScript disabled, since what remains visible is close to what crawl-stage indexing sees before rendering.
From there, a few checks isolate the common stalls. Watch the “Crawled – currently not indexed” report, since sudden growth there usually points to a quality or duplicate-detection change rather than a crawl problem. Audit robots.txt for any script, style, or API resource the page needs to render, because self-blocking those resources produces rendering failures Google reports only vaguely. Check render time on important templates, since pages that take several seconds to become interactive are the ones most exposed to the timeout. And look for hydration mismatches, where the HTML response and the rendered DOM disagree on SEO-relevant content in ways that produce inconsistent indexation.
What site owners actually control #
The pipeline runs on Google’s schedule, but several inputs are firmly within site control. Putting SEO-critical content directly in the HTML response is the single largest lever: titles, meta descriptions, headings, body copy, structured data, and primary navigation should all be present before any JavaScript runs, so the rendering stage becomes an enhancement rather than a dependency. Faster render performance raises success rates in the queue, which means trimming JavaScript bundle size, cutting third-party scripts, and clearing render-blocking resources. Every resource the page needs must be reachable, so robots.txt and CDN rules should never block CSS, JavaScript, or the API endpoints the page calls. Internal links from strong pages signal priority and pull URLs through crawl and render faster than orphaned pages move. And a sitemap that lists the genuinely important URLs concentrates attention, while one padded with thousands of low-value URLs dilutes the signal.
The through-line is that the pipeline rewards sites that make Google’s work easy. Clean HTML, fast rendering, reachable resources, and clear priority signals get indexed quickly and consistently, while sites that fight the pipeline pay the latency cost the tail imposes.
FAQ #
Does Google still index in two waves?
Not as two discrete passes. The 2018 two-wave description was a simplification, and by 2019 Google was already calling it less relevant. The pipeline now behaves more like a continuous fetch-render-index queue, though the core intuition still holds: HTML content indexes faster than JavaScript-built content.
Does JavaScript content really take weeks to get indexed?
For most sites, no. Recent data puts the median render delay in the seconds range and the common case in seconds to minutes. Long waits happen at the tail, for low-authority or infrequently crawled URLs with heavy JavaScript, not as the normal outcome.
Does Google render every page or only JavaScript-heavy ones?
Effectively every indexable HTML page. Rendering is cheap enough that Google runs static pages through it too, so the old idea that only JavaScript-heavy pages get rendered no longer describes the system.
Why is one page indexed while another from the same template is not?
Because indexation is decided per URL, not per template. A single timeout, a lazy-loaded block that never triggered, a duplicate-content match, or a quality judgment can stop one URL while its template-mates pass.
Where do I see which stage a URL failed at?
The URL Inspection tool shows the crawl result, the rendered HTML, and the indexing state, and the “Crawled – currently not indexed” report captures URLs that cleared crawl but stopped before serving. Together they usually point at the failing stage.
The value of the pipeline model is diagnostic more than prescriptive. “Google indexed my page” and “Google didn’t index my page” collapse a multi-stage decision into a coin flip, when the reality is a chain of stages that each succeed, fail, or stall on their own terms. A page that never appears failed somewhere specific in that chain, and finding the specific stage, rather than treating the whole thing as a black box, is what separates technical SEO that fixes problems from technical SEO that guesses at them.