---
title: "Test how Googlebot renders your JavaScript site and close the indexing gaps"
description: "See what Googlebot gets before and after rendering, find the JavaScript patterns that hide content, and pick SSR, SSG, or ISR for each route."
canonical: "https://scalewithsearch.com/articles/googlebot-javascript-rendering"
date: "2026-03-20"
modified: "2026-09-25"
---
## Site navigation

- [Scale With Search](https://scalewithsearch.com/)
- Real estate
  - Real estate
    - [Real estate](https://scalewithsearch.com/for/real-estate)
- Work
  - Start here
    - [Send your brief](https://scalewithsearch.com/work#send-your-brief)
    - [Prepare your six-question brief](https://scalewithsearch.com/work#prepare-your-six-question-brief)
  - Build
    - [Site build, content library with SEO, signal desk](https://scalewithsearch.com/work)
- For your business
  - Trades and home services
    - [Auto body and collision shops](https://scalewithsearch.com/for/auto-body-and-collision-shops)
    - [Foundation and home repair contractors](https://scalewithsearch.com/for/foundation-and-home-repair)
    - [Garage door and fencing contractors](https://scalewithsearch.com/for/garage-door-and-fencing-contractors)
    - [HVAC contractors](https://scalewithsearch.com/for/hvac-contractors)
    - [Janitorial and commercial cleaning companies](https://scalewithsearch.com/for/janitorial-and-commercial-cleaning)
    - [Locksmiths](https://scalewithsearch.com/for/locksmiths)
    - [Moving companies](https://scalewithsearch.com/for/moving-companies)
    - [Pest control companies](https://scalewithsearch.com/for/pest-control-companies)
    - [Plumbing and electrical contractors](https://scalewithsearch.com/for/plumbing-and-electrical-contractors)
    - [Restoration and water or fire damage companies](https://scalewithsearch.com/for/restoration-and-water-fire-damage)
    - [Roofing companies](https://scalewithsearch.com/for/roofing-companies)
    - [Towing companies](https://scalewithsearch.com/for/towing-companies)
    - [Tree services and landscaping companies](https://scalewithsearch.com/for/tree-services-and-landscaping)
    - [Solar installers](https://scalewithsearch.com/for/solar-installation)
    - [General contractors](https://scalewithsearch.com/for/general-contractors-and-construction)
    - [Paving, concrete, and flooring contractors](https://scalewithsearch.com/for/paving)
  - Practices and professional services
    - [Bookkeeping and tax practices](https://scalewithsearch.com/for/bookkeeping-and-tax-practices)
    - [Dental practices](https://scalewithsearch.com/for/dental-practices)
    - [Family and criminal defense law firms](https://scalewithsearch.com/for/family-and-criminal-defense-law-firms)
    - [Med spas and aesthetics practices](https://scalewithsearch.com/for/med-spas-and-aesthetics)
    - [Personal injury law firms](https://scalewithsearch.com/for/personal-injury-law-firms)
    - [Veterinary clinics](https://scalewithsearch.com/for/veterinary-clinics)
    - [Gyms and fitness studios](https://scalewithsearch.com/for/fitness)
    - [Therapy and outpatient health practices](https://scalewithsearch.com/for/therapy-and-outpatient-health)
    - [Medical billing companies](https://scalewithsearch.com/for/medical-billing)
    - [Insurance agencies](https://scalewithsearch.com/for/insurance-agencies)
    - [Financial advisors](https://scalewithsearch.com/for/financial-advisors)
    - [Property management companies](https://scalewithsearch.com/for/property-management)
    - [Recruiting and staffing agencies](https://scalewithsearch.com/for/recruiting-and-staffing)
    - [Architects and interior designers](https://scalewithsearch.com/for/architects-and-interior-designers)
    - [Logistics and supply chain companies](https://scalewithsearch.com/for/logistics-and-supply-chain)
  - Agencies, MSPs, and manufacturing
    - [IT and managed service providers](https://scalewithsearch.com/for/it-and-managed-service-providers)
    - [Machine shops and precision manufacturers](https://scalewithsearch.com/for/machine-shops-and-precision-manufacturing)
    - [Marketing agencies and freelancers](https://scalewithsearch.com/for/marketing-agencies-and-freelancers)
    - [SEO agencies and consultants](https://scalewithsearch.com/for/seo-agencies-and-consultants)
    - [Small manufacturers and fabricators](https://scalewithsearch.com/for/small-manufacturers-and-fabricators)
  - Restaurants, shops, studios, and nonprofits
    - [Restaurants and hospitality businesses](https://scalewithsearch.com/for/restaurants-and-hospitality)
    - [Retail stores and ecommerce sellers](https://scalewithsearch.com/for/retail-and-ecommerce)
    - [Photographers, event planners, and travel agents](https://scalewithsearch.com/for/photographers)
    - [Churches and nonprofits](https://scalewithsearch.com/for/churches-and-nonprofits)
  - [All industries](https://scalewithsearch.com/for/)
- Learn
  - For your office
    - [Office job guides](https://scalewithsearch.com/guides/)
    - [Browser calculators](https://scalewithsearch.com/tools/)
  - Start here
    - [How it works](https://scalewithsearch.com/how-it-works)
    - [Free Starter Kit](https://scalewithsearch.com/kit/business-memory-starter-kit.zip)
    - [Synthetic specimen](https://scalewithsearch.com/specimen/working-session-specimen.zip)
  - Guides
    - [The Complete Guide to Business Memory for AI Agents](https://scalewithsearch.com/articles/business-memory-for-ai-agents-guide)
    - [The Complete Small-Business Guide to AI Agent Governance](https://scalewithsearch.com/articles/ai-agent-governance-guide-small-business)
    - [The Complete Guide to Leaving Vendor AI Memory](https://scalewithsearch.com/articles/leaving-vendor-ai-memory-guide)
  - Articles by cluster
    - [Business memory](https://scalewithsearch.com/articles/business-memory-for-ai-agents-guide)
    - [Agent governance](https://scalewithsearch.com/articles/ai-agent-governance-guide-small-business)
    - [Migration and ownership](https://scalewithsearch.com/articles/leaving-vendor-ai-memory-guide)
  - For machines
    - [llms.txt](https://scalewithsearch.com/llms.txt)
    - [llms-full.txt](https://scalewithsearch.com/llms-full.txt)
    - [Machine view](https://scalewithsearch.com/?view=machine)
- Company
  - Evidence
    - [Proof](https://scalewithsearch.com/proof)
  - Company
    - [About](https://scalewithsearch.com/about)

# Test how Googlebot renders your JavaScript site and close the indexing gaps.

A team ships a React single-page app. The pages look complete in every browser. Three months later, Google Search shows the page title "Loading..." for half of the product pages, and the rest are missing.

Google renders JavaScript with an evergreen version of Chromium. That statement is true, but it does not mean every JavaScript page gets indexed with its full content. Rendering happens after crawling, and some patterns fail during rendering. This article explains how Googlebot processes JavaScript and which patterns hide content. It then shows how to test what Google sees and which rendering method fits each framework.

## Understand the two stages

Googlebot processes a JavaScript page in two stages: crawl, then render.

### Stage 1: crawl the HTML

Googlebot fetches the HTML response from your server. For a static HTML page, that response holds all the content. For a client-rendered app, the response often looks like this:

```html
<!DOCTYPE html>
<html>
<head>
<title>Loading...</title>
</head>
<body>
<div id="root"></div>
<script src="/bundle.js"></script>
</body>
</html>
```

This HTML has no content. JavaScript builds the whole page after load.

### Stage 2: render in a queue

Google puts pages into a render queue. A headless Chromium instance runs the JavaScript, waits for the page to settle, captures the rendered HTML, and indexes the content from it. The wait is a heuristic. It is not a fixed timer that you can rely on.

Google's Martin Splitt spoke about this delay at Chrome Dev Summit in 2019. He said the median time from crawl to render was about five seconds, with a long tail. Your site can differ. The risk is not only delay. If rendering fails or stops early, Google indexes what it has, which can be the empty shell from stage 1.

One more rule matters. If the HTML from stage 1 contains `noindex`, Google can skip rendering. JavaScript that later removes the `noindex` tag does not help.

## Recognize the patterns that fail

### Continuous polling or long waits

A page that polls an API forever never reaches a settled state:

```javascript
// Polling that never stops
setInterval(() => {
  fetchUpdates();
}, 5000);
```

Google does not publish a render timeout. A page that keeps the network busy risks a render with partial content. Load the content once at page load. If you must poll, start after the main content is on the page.

### Content behind a login

Googlebot does not log in, and it does not keep cookies or local storage between page loads. User dashboards, gated content, and pages that need a session cookie are not indexed. Make public content available without a login, and render those pages on the server.

### Client-side redirects

A JavaScript redirect such as `window.location = '/new-page'` works only after Google renders the page:

```javascript
if (oldPage) {
  window.location = '/new-page';
}
```

Google can follow it, but the signal is weaker and slower than a server redirect. Use an HTTP 301 or 308 redirect on the server for every permanent URL change. The [301 redirect guide for developers](/articles/redirect-chains-301-developers) covers chains and loops.

### Content that loads on scroll

Googlebot does not scroll like a person. It renders with a tall viewport, but it does not fire scroll events that your code waits for:

```javascript
// Content loads only on a scroll event
window.addEventListener('scroll', () => {
  if (isNearBottom()) {
    loadMoreContent();
  }
});
```

Render the main content at load. Use an `IntersectionObserver` or native `loading="lazy"` for images and below-the-fold extras. The [lazy loading implementation guide](/articles/lazy-loading-seo-implementation) shows safe patterns.

### Slow API calls

A page that fetches its content from a slow API can render before the data arrives:

```javascript
// Slow API call
fetch('/api/products?limit=100')
  .then(res => res.json())
  .then(data => renderProducts(data));
```

Keep API responses under 500 milliseconds for content that must be indexed. The safer fix is to fetch the data on the server and send it in the HTML.

## Test what Google sees

### URL Inspection in Search Console

1. Open Google Search Console.
2. Enter the URL in the `URL Inspection` field.
3. Select `Test live URL`.
4. Select `View tested page`, then check the `Screenshot` and `HTML` tabs.

If the screenshot is blank or the HTML has no body text, rendering failed. This test shows the current render. An earlier crawl can differ, so compare it with the indexed version in the same report.

### Rich Results Test

Google retired the Mobile-Friendly Test in December 2023. The Rich Results Test at `search.google.com/test/rich-results` still renders a page with Googlebot and shows the rendered HTML. It works for pages on sites you do not own in Search Console, such as a staging URL that is public.

### Screaming Frog with rendering on

1. Open Screaming Frog SEO Spider.
2. Go to `Configuration`, then `Spider`, then `Rendering`.
3. Set rendering to `JavaScript`.
4. Crawl the site.
5. Compare the original HTML with the rendered HTML for each page.

Pages with no content in the original HTML depend on JavaScript. Pages with no content in either version failed to render.

### Chrome with JavaScript turned off

1. Open the page in Chrome and open DevTools.
2. Open the Command Menu with `Ctrl+Shift+P`, or `Cmd+Shift+P` on a Mac.
3. Type `Disable JavaScript` and press Enter.
4. Reload the page.

This view is close to what Googlebot has in stage 1. If the page is blank, every word of content depends on rendering.

## Fix each framework

### React

Create React App produces an empty HTML shell. The React team deprecated Create React App in February 2025 and points new projects to frameworks. For SEO pages, move to a framework that renders on the server or at build time.

Next.js is the common choice. It sends complete HTML in stage 1, so the page does not depend on the render queue:

1. Create a project with `npx create-next-app@latest`.
2. Move the React components into Next.js routes. Most components move with few changes.
3. Deploy with server rendering or static generation turned on.

If a page changes rarely, generate it at build time. This example uses the Pages Router:

```javascript
export async function getStaticProps() {
  const data = await fetchProducts();
  return { props: { products: data } };
}
```

The HTML then holds the content, and indexing needs no client-side JavaScript.

### Vue

A Vue app built with Vue CLI has the same empty shell. Vue CLI is in maintenance mode, and new Vue projects use Vite.

Nuxt is to Vue what Next.js is to React. It renders Vue components into HTML on the server. For Nuxt 3, create a project with `npx nuxi@latest init`. Older guides use `npx create-nuxt-app`, which set up Nuxt 2. Move the Vue components into Nuxt pages and deploy with server rendering.

For a small Vue CLI site, you can prerender each route at build time:

```bash
npm install vue-cli-plugin-prerender-spa
```

The build then writes a static HTML file for each route.

### Angular

An Angular app is a single-page application with client-side routing. Angular Universal was the original server-rendering package. Since Angular 17 (November 2023), server rendering is part of the Angular CLI:

```bash
ng add @angular/ssr
```

Projects on older versions used `ng add @nguniversal/express-engine`. Either way, the server sends rendered HTML to Googlebot.

### Next.js

Next.js renders on the server by default, but configuration can undo that. To check, view the page source with `Ctrl+U` or `Cmd+U`. The content must appear in the raw HTML, not only an empty `<div id="__next"></div>`.

In the App Router, Server Components render on the server by default. Fetch data in a Server Component, not in a client `useEffect`. In the Pages Router, watch for two mistakes.

The first mistake is `getInitialProps` in the custom `App` component. It turns off automatic static optimization for every page. Use `getStaticProps` or `getServerSideProps` on each page instead.

The second mistake is client-side data fetching:

```javascript
useEffect(() => {
  fetch('/api/data')
    .then(res => res.json())
    .then(setData);
}, []);
```

The data is not in the HTML that Googlebot receives first. Fetch it on the server:

```javascript
export async function getServerSideProps() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();
  return { props: { data } };
}
```

## Treat dynamic rendering as a stopgap

Dynamic rendering sends prerendered HTML to bots and the normal JavaScript app to users:

1. Detect the crawler by its user agent.
2. Send a bot prerendered HTML from Prerender.io or your own headless Chrome.
3. Send a user the normal JavaScript app.

It gives crawlers HTML without a change to the app architecture. It adds infrastructure, and the bot version must match the user version, or it becomes cloaking. Google's documentation now calls dynamic rendering a workaround, not a recommended solution. Use it only while you move to server rendering or static generation. Prerender.io is a paid hosted service. Google deprecated its own open-source option, Rendertron, in 2022, so do not start a new setup on it.

## Choose SSR, SSG, or ISR for each route

The [server-side rendering guide](/articles/server-side-rendering-seo) compares these methods in more depth.

Use server-side rendering (SSR) in three cases. The content changes often, such as prices, stock, or news. The page shows personal data. Or the site has many dynamic routes, such as `/products/[id]` with thousands of IDs. The cost is server load, because every request renders on the server.

Use static site generation (SSG) when content changes rarely, such as marketing pages and articles. SSG also fits predictable routes and pages where speed matters most. Static files load fastest. The cost is a rebuild for each content change.

Use incremental static regeneration (ISR) in Next.js for a mix. Pages build once and regenerate in the background after a set time:

```javascript
export async function getStaticProps() {
  const data = await fetchProducts();
  return {
    props: { products: data },
    revalidate: 3600, // Regenerate at most once each hour
  };
}
```

In the App Router, the same result comes from `export const revalidate = 3600` in the route file.

## Know Googlebot's limits

Googlebot renders modern JavaScript (ES6 and later), CSS including CSS-in-JS, and Web Components. It fetches over HTTP/1.1 and HTTP/2.

Googlebot does not use service workers. It declines permission requests such as camera, microphone, and location. It does not keep cookies or storage between page loads. It does not click or scroll to trigger content. Very slow pages risk partial renders. Test with URL Inspection to confirm each template renders.

Google can index JavaScript pages, but the risk is uneven. A simple page that renders fast often indexes well. SSR or SSG removes the risk for pages that must rank.

Vanilla JavaScript is not safer by itself. It is safer only when it puts the content in the initial HTML. JavaScript does not hurt rankings when the content renders and the page is fast. Slow scripts hurt Core Web Vitals, and render delays hurt indexing.

The [JavaScript SEO guide](/articles/javascript-seo-guide) covers links, metadata, and structured data on JavaScript sites.

## Check each JavaScript page before release

- Main content is in the initial HTML, through SSR or SSG.
- Internal links are `<a href>` elements, not click handlers.
- No polling loop keeps the network busy.
- API calls for indexed content return in under 500 milliseconds.
- The title and meta description are in the HTML before JavaScript runs.
- Structured data (JSON-LD) is in the server HTML. Google can read JSON-LD that JavaScript adds, but server output is safer.
- Images have a `src` in the HTML, or use native `loading="lazy"`.
- `robots.txt` does not block JavaScript or CSS files.
- Redirects are HTTP 301, 302, 307, or 308, not client-side.
- The URL Inspection render matches what a user sees.

----

```text
                  .|########||.                                       .|########||.                                       .|########||.
               |##||.      .||##|.                                 |##||.      .||##|.                                 |##||.      .||##|.
             |#|.              .|#|.                             |#|.              .|#|.                             |#|.              .|#|.
           |#|                    |#|                          |#|                    |#|                          |#|                    |#|
         .#|                        |#.                      .#|                        |#.                      .#|                        |#.
        .#.                          .#|                    .#.                          .#|                    .#.                          .#|
       |#.                            .#|                  |#.                            .#|                  |#.                            .#|
      |#             ......             #|                |#             ......             #|                |#             ......             #|
     .#           ||#########|           #|              .#           ||#########|           #|              .#           ||#########|           #|
    .#.         |######||######|.        .#.            .#.         |######||######|.        .#.            .#.         |######||######|.        .#.
    #.        .##|###|##|#|######|        .#            #.        .##|###|##|#|######|        .#            #.        .##|###|##|#|######|        .#
   ||        |##|#||||||||||||#||#|        ||          ||        |##|#||||||||||||#||#|        ||          ||        |##|#||||||||||||#||#|        ||
   #        |#||||||||||||||||||||#|        #.         #        |#||||||||||||||||||||#|        #.         #        |#||||||||||||||||||||#|        #.
  ||       |#||||||||||||||||||||||#|       ||        ||       |#||||||||||||||||||||||#|       ||        ||       |#||||||||||||||||||||||#|       ||
  #       .#||||||||||||||||||||||||#|       #        #       .#||||||||||||||||||||||||#|       #        #       .#||||||||||||||||||||||||#|       #
 ||   ....|||#||||||##|#|||#|#||##||||....|. ||      ||   ....|||#||||||##|#|||#|#||##||||....|. ||      ||   ....|||#||||||##|#|||#|#||##||||....|. ||
 #.  .  ....|#  ....#|||   ||| .#|||  ....#. .#      #.  .  ....|#  ....#|||   ||| .#|||  ....#. .#      #.  .  ....|#  ....#|||   ||| .#|||  ....#. .#
 #   .  ||||#| .#####||  . .#| .#|||  ||||#   #.     #   .  ||||#| .#####||  . .#| .#|||  ||||#   #.     #   .  ||||#| .#####||  . .#| .#|||  ||||#   #.
.|   |||||  #. |#|||||. ||  #. |#||. .|||||   ||    .|   |||||  #. |#|||||. ||  #. |#||. .|||||   ||    .|   |||||  #. |#|||||. ||  #. |#||. .|||||   ||
||   |....  #. ....|#.      |. ...|. ....||   ||    ||   |....  #. ....|#.      |. ...|. ....||   ||    ||   |....  #. ....|#.      |. ...|. ....||   ||
#.  .||||||##||||||##||####|||||||#||||||#|   .#    #.  .||||||##||||||##||####|||||||#||||||#|   .#    #.  .||||||##||||||##||####|||||||#||||||#|   .#
#    .||####|###########################|.     #    #    .||####|###########################|.     #    #    .||####|###########################|.     #
#      .#||||||.#.|| # |. ..# #| #|||||#|      #    #      .#||||||.#.|| # |. ..# #| #|||||#|      #    #      .#||||||.#.|| # |. ..# #| #|||||#|      #
#      .#|||||| ..  |# ## |#| ...#|#|||#|      #    #      .#|||||| ..  |# ## |#| ...#|#|||#|      #    #      .#|||||| ..  |# ## |#| ...#|#|||#|      #
#      .#|||#|# .# .#| #| ##|.#..#|||||#|      #    #      .#|||#|# .# .#| #| ##|.#..#|||||#|      #    #      .#|||#|# .# .#| #| ##|.#..#|||||#|      #
#      .#||||||############|######|||||#|      #    #      .#||||||############|######|||||#|      #    #      .#||||||############|######|||||#|      #
#   |...||#||||||#||||#|#||||||#|||||#||| |.|  #    #   |...||#||||||#||||#|#||||||#|||||#||| |.|  #    #   |...||#||||||#||||#|#||||||#|||||#||| |.|  #
#. .. ||||# .|||##|.  |#| .|| || .|||#. #|  # .#    #. .. ||||# .|||##|.  |#| .|| || .|||#. #|  # .#    #. .. ||||# .|||##|.  |#| .|| || .|||#. #|  # .#
|| |  ...||  ...##| |  #| .|. |. #####  .. .| ||    || |  ...||  ...##| |  #| .|. |. #####  .. .| ||    || |  ...||  ...##| |  #| .|. |. #####  .. .| ||
|| ||||| || ||||#|  .  |. |. |#. ||||| |#| || ||    || ||||| || ||||#|  .  |. |. |#. ||||| |#| || ||    || ||||| || ||||#|  .  |. |. |#. ||||| |#| || ||
.# |.....#|....|#.||||.|||##.|#|....||.#||.#. #.    .# |.....#|....|#.||||.|||##.|#|....||.#||.#. #.    .# |.....#|....|#.||||.|||##.|#|....||.#||.#. #.
 #.|||||||#############################| ||| .#      #.|||||||#############################| ||| .#      #.|||||||#############################| ||| .#
 ||       ##||#||#||||||#||#||#||#||##.      ||      ||       ##||#||#||||||#||#||#||#||##.      ||      ||       ##||#||#||||||#||#||#||#||##.      ||
  #       .#|||||||||#||#|||||||||||#|       #        #       .#|||||||||#||#|||||||||||#|       #        #       .#|||||||||#||#|||||||||||#|       #
  ||       |#||||||||||||||||||||||#|       ||        ||       |#||||||||||||||||||||||#|       ||        ||       |#||||||||||||||||||||||#|       ||
  .#        |#||||||||||||||||||||#|        #.        .#        |#||||||||||||||||||||#|        #.        .#        |#||||||||||||||||||||#|        #.
   ||        |#||||||||||||||||||#|        ||          ||        |#||||||||||||||||||#|        ||          ||        |#||||||||||||||||||#|        ||
    #.        .######|#|#########|        .#            #.        .######|#|#########|        .#            #.        .######|#|#########|        .#
    .#.         |#####||||#####|         .#.            .#.         |#####||||#####|         .#.            .#.         |#####||||#####|         .#.
     |#           ||########||           #.              |#           ||########||           #.              |#           ||########||           #.
      |#             ......             #|                |#             ......             #|                |#             ......             #|
       |#.                            .#|                  |#.                            .#|                  |#.                            .#|
        |#.                          .#.                    |#.                          .#.                    |#.                          .#.
         .#|                        |#.                      .#|                        |#.                      .#|                        |#.
           |#|                    |#|                          |#|                    |#|                          |#|                    |#|
            .|#|.              .|#|.                            .|#|.              .|#|.                            .|#|.              .|#|.
               |##||.      .||##|                                  |##||.      .||##|                                  |##||.      .||##|
                 .||########||.                                      .||########||.                                      .||########||.

Scale With Search  2026  [scalewithsearch.com](https://scalewithsearch.com)
```
