Skip to content

JavaScript SEO: why your site can look empty to Google and AI crawlers

By the Growli teamUpdated 7 min read

Short answer

JavaScript SEO is making sure crawlers can read content that JavaScript builds in the browser. Googlebot renders JavaScript, sometimes after a delay, but most AI crawlers are not documented to do so and should be assumed to read only the initial HTML. Put key text, links and metadata in that HTML using server-side rendering or static generation.

Test your site in 5 steps

  1. Step 1: Open the raw HTML of your page

    Right-click the page and choose "View page source" (Ctrl+U on Windows, Cmd+Option+U on a Mac).

  2. Step 2: Search for a sentence from your main content

    Press Ctrl+F (Cmd+F) and search. If the sentence is not in the source, crawlers that do not run JavaScript see an empty page.

  3. Step 3: Check what Google sees

    In Google Search Console, inspect the page address, click "Test live URL" and view the tested page's HTML.

    Open Search Console
  4. Step 4: Fix it with server-side rendering

    Switch on server-side rendering or static generation in your framework (Next.js, Nuxt and others support it), or use a prerendering service.

  5. Step 5: Test again

    Repeat steps 1 and 2. A free Growli audit also compares your raw HTML with the rendered page.

    Run a free audit

Why can a JavaScript site look empty to crawlers?

Many modern sites send the browser an almost blank HTML page plus a bundle of JavaScript. The browser runs that code, which then fetches data and builds the text, images and menus you see. This is called client-side rendering.

A person never notices, because their browser runs the code in a fraction of a second. A crawler that only downloads the HTML and does not run JavaScript sees something closer to this:

What the raw HTML of a client-rendered page can look like
<!doctype html>
<html>
  <head>
    <title>Loading...</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="/assets/app.js"></script>
  </body>
</html>

No headings, no product descriptions, no links to other pages. To that crawler, the page is empty. Search engines and AI assistants can only rank, cite or recommend what they can read.

How Googlebot handles JavaScript

Google documents three phases for JavaScript pages: crawling, rendering and indexing. Googlebot first fetches the HTML and checks robots.txt. Pages that return a 200 status then go into a render queue, where a headless Chromium browser runs the JavaScript once Google's resources allow.

Google says a page may wait in that queue for a few seconds, but it can take longer. After rendering, Google indexes the rendered HTML and looks for more links to crawl. The details are in Google's JavaScript SEO basics.

A few points from that guide catch many sites out:

  • Google only discovers links that are <a> elements with an href attribute. Buttons or divs that change the page with a click handler are not followed as links.
  • If the original HTML contains a noindex tag, Google may skip rendering, so removing noindex with JavaScript may not work.
  • If robots.txt blocks your JavaScript files or API endpoints, Google cannot render what depends on them.
  • Google itself notes that not all bots can run JavaScript, and still calls server-side rendering or prerendering a great idea.

Do AI crawlers run JavaScript?

This is where it pays to be careful with claims. OpenAI, Anthropic and Perplexity document their crawler names and what each one is for, but as of October 2026 none of them publicly documents whether their crawlers execute JavaScript. There is no official statement either way.

What is known comes from independent server log analyses, which have generally reported that the main AI crawlers fetch raw HTML and do not run JavaScript. Some fetch script files without executing them. Vendors can change this at any time, and user-triggered fetches or browser-based agents may behave differently from background crawlers.

The practical conclusion does not depend on the details: if your important content exists only after JavaScript runs, assume AI crawlers will miss it. Google's ability to render does not carry over to other bots. Making sure those bots are allowed in the first place is a separate step, covered in our guide to robots.txt for AI crawlers.

  • Crawler
    Googlebot
    Runs JavaScript?
    Yes, in a render queue, sometimes delayed
    Source
    Documented by Google
  • Crawler
    GPTBot, OAI-SearchBot
    Runs JavaScript?
    Not documented
    Source
    Independent log studies suggest no
  • Crawler
    ClaudeBot, Claude-SearchBot
    Runs JavaScript?
    Not documented
    Source
    Independent log studies suggest no
  • Crawler
    PerplexityBot
    Runs JavaScript?
    Not documented
    Source
    Assume no

How to test what a crawler actually sees

You do not need special software to check. The key is to look at the HTML your server sends, not the page your browser has finished building.

  1. View source. Right-click the page and choose View page source (or type view-source: before the URL in Chrome). Search for a sentence from your main content. If it is not there, it is added by JavaScript. Note that the Inspect or Elements panel shows the page after JavaScript ran, so it is not a fair test.
  2. Fetch with curl. In a terminal, request the page and search the output for a phrase, as shown below. Sending a crawler's user agent name can also reveal firewalls that treat bots differently.
  3. Disable JavaScript. Turn JavaScript off in your browser's site settings and reload. What remains is roughly what a non-rendering crawler gets.
  4. Use Google's URL Inspection tool. In Search Console, inspect the URL, click Test live URL, then View tested page to see the rendered HTML and a screenshot. Google's URL Inspection tool help explains each tab.
Terminal
curl -s https://www.example.com/pricing | grep -i "monthly plan"

curl -s -A "GPTBot" -o /dev/null -w "%{http_code}\n" https://www.example.com/

If you have not connected Search Console yet, our Google Search Console setup guide walks through verification. To check many pages at once, you can run a free Growli audit: it reads your site the way Google and AI crawlers do and flags content that only appears after JavaScript runs.

Fixes: get your content into the initial HTML

The goal of every fix is the same: the HTML your server sends should already contain the content, links and metadata that matter. There are a few ways to get there.

  • Server-side rendering (SSR). The server runs your app for each request and sends finished HTML. JavaScript then takes over in the browser (called hydration). Good for pages that change often or depend on the visitor.
  • Static generation. Pages are built into HTML files ahead of time, at build or on a schedule. Fast and reliable for content that does not change every minute, such as blog posts, service pages and documentation.
  • Prerendering. A tool or service renders your client-side pages into HTML and serves that snapshot. Useful when rebuilding the app is not realistic, but it adds another moving part.

Google now describes dynamic rendering, which means serving prerendered HTML only to bots, as a workaround rather than a long-term solution. Its dynamic rendering page recommends server-side rendering, static rendering or hydration instead.

What must be in the initial HTML

  • The title tag and meta description (see our guide to title tags and meta descriptions).
  • The main heading and the body text that answers the page's question.
  • Navigation and internal links as real <a href> links.
  • Canonical tag, robots meta tag and structured data (JSON-LD).
  • Product names, prices, opening hours or other facts you want quoted.

Content behind tabs or accordions is fine, as long as the text is in the HTML and only hidden visually. Content that loads only when someone clicks or scrolls is the risk.

Framework and website builder notes

Your setup decides how much work this is. These are general patterns, so always confirm with the tests above rather than assuming.

  • Next.js. With the App Router, components are Server Components by default and render on the server. Client Components are also rendered to HTML on the first load, but data fetched in the browser after the page loads (for example in useEffect) will not be in the initial HTML. See the Next.js docs on server and client components.
  • Nuxt. Nuxt uses universal rendering by default, so pages arrive as HTML. Setting ssr to false turns the app into a client-rendered single-page app, which brings back the empty-page problem. The Nuxt rendering docs explain the modes.
  • Plain React single-page apps. A typical setup created with Vite ships an empty root element and builds everything in the browser. Moving to a framework with SSR or static generation, or prerendering key routes, is the usual fix.
  • Wix, Squarespace and similar builders. These platforms serve HTML for their standard page elements, so core text is usually visible. Third-party widgets, embedded apps, review feeds and iframes may load with JavaScript, so test the pages that rely on them.
  • WordPress and Shopify. Themes normally render HTML on the server. Problems tend to come from page builder add-ons, apps or scripts that inject content after load.

Common JavaScript SEO mistakes to check

Beyond rendering itself, a handful of patterns cause most problems. Each one is easy to spot once you look at the raw HTML.

  • Every page shares the same title and description because they are set in JavaScript after load.
  • Structured data is injected by a tag manager, so it only exists after scripts run. Our guide to schema markup for AI search covers how to add it directly.
  • Pagination or "load more" buttons hide products and posts behind clicks with no crawlable link.
  • Error pages return a 200 status with a "not found" message drawn by JavaScript, instead of a real 404.
  • The page shows a loading spinner or cookie wall in the HTML while the real content waits for scripts.

Frequently asked questions

Is JavaScript bad for SEO?

No. JavaScript is fine for interactivity, and Google can render it. The problem is relying on it to create the main content, links and metadata, because rendering can be delayed for Google and may not happen at all for other crawlers.

Does ChatGPT see content loaded with JavaScript?

OpenAI does not document whether its crawlers run JavaScript. Independent log analyses suggest they read raw HTML, so content that only appears after scripts run should be treated as likely invisible to ChatGPT's crawlers.

How long does Google take to render JavaScript?

Google says a page may sit in the render queue for a few seconds, but it can take longer, and it gives no fixed time. Pages whose content is in the initial HTML can be understood straight away from the first crawl.

Is serving prerendered HTML to bots considered cloaking?

Google says dynamic rendering is generally not cloaking as long as bots and users get similar content. It still calls the approach a workaround, so server-side rendering or static generation is the better long-term choice.