JavaScript SEO in 2026: Rendering Choices (When Google Renders JS and AI Crawlers Don’t)
.jpg?apiKey=6720fb7d4af2f1ddaa6bbdf6.c00cf44655f4c098ecc0082a201e6c7eaef24cda05e94d2845e3c7a12ae6773b)
The comfortable take on JavaScript SEO in 2026 goes like this: Google renders JavaScript now, so the whole problem is solved, ship your React app and move on. That’s half right. Googlebot does render your JavaScript, and it does it well. The trouble is that Google is no longer the only machine reading your site that you care about.
The crawlers feeding ChatGPT, Claude, and Perplexity pull your raw HTML and stop there. They don’t run your JavaScript. So a single-page app with no server rendering can rank perfectly well in Google and be completely invisible everywhere an AI model looks. And the part that stings: your Google rankings won’t warn you it’s happening.
This guide walks through how Google handles your JavaScript, why the other crawlers behave differently, what CSR, SSR, and SSG do to your visibility, and how to check and fix all of it without rebuilding a site that was fine to begin with.
Key Takeaways
Google renders your JavaScript. The other crawlers don't. Vercel's analysis of 569 million GPTBot requests found zero JavaScript execution across any of the major AI crawlers.
Your Google rankings won't warn you. A page can rank #1 in Google and return an empty content div to every crawler feeding an AI answer.
Rendering is a per-template decision, not a site-wide one. Login pages can stay client-side. Marketing pages, docs, and product templates need content in the initial HTML.
SSR and SSG both fix the crawler problem. SSG for stable content, SSR for per-request or personalized pages, ISR for content that changes on a schedule.
The whole test is "View Source." If the raw HTML contains your content, every crawler can read it. If it only shows an empty root div, your content is invisible to anything that doesn't render.
Structured data belongs server-side. JSON-LD injected client-side has the same problem as everything else, AI crawlers never see it.
Real <a href> links matter as much as rendered content. Navigation built from onclick handlers or client-side routers with no real URLs gives a crawler nothing to follow.
Don't rebuild what already works. If View Source shows your content, keep your setup. Fix the templates that are actually failing, not your entire architecture.
How Google Handles JavaScript (Crawl, Render, Index)
%20-%20Image%201.jpg?apiKey=6720fb7d4af2f1ddaa6bbdf6.c00cf44655f4c098ecc0082a201e6c7eaef24cda05e94d2845e3c7a12ae6773b)
Start with the good news, because the Google side of JavaScript SEO genuinely is close to solved. Google processes a JavaScript site in three phases. It crawls the URL, it renders the page, then it indexes what the rendering produced. These aren’t the same step, and the gap between them is where most JavaScript SEO problems live.
When Googlebot fetches a URL and gets a 200 HTTP status code, it queues that page for rendering. Rendering happens in the Web Rendering Service, which runs a headless, evergreen version of Chromium, the same engine underneath the browser you’re reading this in. That’s a real browser executing your JavaScript, building the DOM, and handing the final HTML to the indexer.
Vercel and Merj's large-scale analysis backs this up. Google doesn't run a separate, slower pipeline for JavaScript-heavy pages, and their controlled testing found no meaningful difference in rendering success based on how much JavaScript a page ships. If your page returns a 200 and isn't blocked, Google will try to render it. For a plain HTML site or a well-built framework app, that usually just works.
The rendering queue and why timing still matters
Crawling and rendering are decoupled for a reason. Rendering is expensive. Running a full browser on billions of pages costs real compute, so Google defers it. Your page gets crawled, sits in a rendering queue, and gets rendered when there’s capacity.
There’s no fixed timeline for how long that wait runs. It can be minutes, hours, or weeks, depending on how often Google crawls your site and how loaded the queue is. For a high-authority news site publishing hourly, rendering is fast. For a new site with thin authority, content that only exists after JavaScript runs can sit un-indexed far longer than the same content served in raw HTML would.
That difference matters most for anything time-sensitive. If your product pages, pricing, or launch content only materialize client-side, you’re voluntarily adding a delay between “published” and “indexed.” Server-rendered content skips the queue entirely, because the content Google needs is already in the first response.
What breaks it: blocked JS, noindex, soft 404s, and rewritten metadata
Even a browser-grade renderer breaks on a few predictable things. Blocking your JavaScript or API endpoints in robots.txt is the classic own-goal. If Googlebot can’t fetch the scripts, it renders an empty shell, and you’ve hidden your own content from the one crawler that would have read it.
A subtler one: a noindex tag in your initial HTML response is honored before rendering ever happens. Studies of Google’s pipeline confirmed that pages carrying noindex in the initial HTML were dropped and never rendered, and trying to remove that tag with client-side JavaScript afterward doesn’t rescue them. The initial response wins.
Then there are soft 404s, where your app returns a 200 status for a page that’s an error or empty state. Google renders it, sees nothing useful, and can quietly drop it.
Metadata deserves its own warning. When JavaScript rewrites your title, canonical, or meta description after load, you end up with two versions of the truth, and crawlers resolve that conflict differently. A canonical injected client-side is invisible to anything that doesn’t render, which means a non-rendering crawler reads the raw version and treats the page as canonical to itself. Set titles and canonicals server-side and let JavaScript leave them alone.
If you want the deeper mechanics of how crawling, rendering, and indexing chain together, our breakdown of how search engine indexing works covers the full pipeline, and the failure modes show up in our list of common indexing problems.
The Crawlers That Don’t Render at All

This is where the “JavaScript SEO is solved” story falls apart. Google is one crawler. The bots feeding AI answers are a different population entirely, and they read your site nothing like Googlebot does.
None of the major AI crawlers currently render JavaScript. Analysis of one month of traffic across a large hosting network, covering 569 million GPTBot requests, found zero JavaScript execution across OpenAI’s OAI-SearchBot and ChatGPT-User, GPTBot, Anthropic’s ClaudeBot, and PerplexityBot. They fetch your HTML, they parse what’s in it, and they leave. Whatever your JavaScript would have built never gets built.
These crawlers are not a rounding error. Together, the four major AI crawlers generated roughly 1.3 billion fetches in that same window, about 28% of Googlebot’s volume. That’s a large and growing slice of the machines reading the open web, and every one of them stops at your raw HTML.
The single exception worth knowing is Gemini. It renders JavaScript because it uses Google's Web Rendering Service, the same infrastructure Googlebot relies on for search indexing — confirmed publicly by Google's Martin Splitt in May 2025. Every other name on the list (GPTBot, ClaudeBot, PerplexityBot, and the rest) sees the un-rendered version of your page.
AI crawlers aren't the only non-rendering readers you have. Bing handles JavaScript less reliably than Google, and social link-preview bots (LinkedIn, X, Facebook, Slack) read only raw HTML, which is why a client-rendered page often shares as a blank card.
Fetching JavaScript isn’t reading it
The most common mistake here is assuming that because an AI crawler requested your JavaScript files, it must have run them. It didn’t. Fetching a script and executing a script are completely different acts, and the data makes the gap obvious.
In that same analysis, JavaScript files made up 11.50% of ChatGPT’s requests and 23.84% of Claude’s. So these bots are pulling your .js files down. But pulling a file is not the same as running it, building the DOM, and reading the result. They fetch the bundle and never execute it. Your content stays locked inside code that nothing on the AI side will ever run.
Two other numbers show how blunt these crawlers still are. They waste a lot of budget on dead URLs, with ChatGPT hitting 404s on 34.82% of its fetches and Claude on 34.16%, against Googlebot’s 8.22%. And they operate from one or two US datacenters rather than Google’s globally distributed setup. This is early-generation crawling. It reads what’s in front of it and nothing more.
Why your rankings won’t tell you
This is the quiet part, and it’s the reason so many teams get caught. If your site ranks well in Google, every dashboard you look at says you’re fine. Rankings are green, impressions are up, the technical audit passes. None of that measures whether an AI crawler can see your content, because Google renders and the AI crawlers don’t.
So a client-side-rendered page can hold page one in Google and return an empty content div to every crawler feeding an AI answer. When someone asks ChatGPT or Perplexity a question your page should answer, your page isn’t in the running. Not because you were outranked, but because you were never readable in the first place. That gap is invisible in your rankings.
This is why rendering has stopped being a performance nicety and become a visibility prerequisite. Getting cited in AI answers depends on your content living in the raw HTML a model’s crawler can read, which is the same foundation behind visibility in AI search. If the content isn’t in the HTML, there’s nothing to cite.
CSR vs SSR vs SSG: What Each Does to Your Visibility

Rendering strategy sounds like an engineering detail. In 2026 it’s a visibility decision, so it’s worth knowing plainly what each option puts in front of a crawler. The whole game is one question. Is your content in the HTML the server sends, or does it only appear after JavaScript runs in a browser?
Three main approaches, plus a couple of hybrids:
Client-side rendering (CSR) ships a near-empty HTML shell plus a JavaScript bundle. The browser downloads the bundle, runs it, and builds the page. Content exists only after execution. This is the default in a plain create-react-app or Vue SPA.
Server-side rendering (SSR) runs your framework on the server for each request and sends fully-formed HTML back. The content is in the first response. The browser then “hydrates” it to make it interactive.
Static site generation (SSG) renders every page to HTML at build time. When a request comes in, the server hands over a pre-built HTML file. Fast, cacheable, content already present.
Hybrids like incremental static regeneration (ISR) and partial hydration mix these, serving static or server-rendered HTML for the content and hydrating only the interactive bits.
The pattern is simple once you see it. SSR and SSG both put your content in the HTML before any JavaScript runs. CSR doesn’t.
One approach you can skip. Dynamic rendering, serving a pre-rendered version to bots and the JavaScript version to humans, was Google’s recommended workaround years ago and is now formally described as a workaround rather than a long-term solution. It adds a second codepath to maintain and a detection step that fails quietly. Server-render the content instead.
Client-side rendering is where content goes dark
For Google, client-side rendering is usually survivable, because the Web Rendering Service will execute your JavaScript and eventually see the content. You pay in rendering delay and fragility, but the content usually gets indexed.
For client-side rendering and AI crawlers, there’s no “eventually.” GPTBot, ClaudeBot, and PerplexityBot fetch your shell, find an empty div where your article should be, and move on. There’s no second pass with a browser. A pure CSR page is, functionally, a blank page to every AI crawler, no matter how rich it looks once your JavaScript has run.
That’s the risk in one line. CSR bets your entire AI-search visibility on a rendering step those crawlers don’t perform.
SSR vs SSG: which fits your content
Both server-side rendering and static generation solve the crawler problem, so choosing between SSR and SSG for SEO comes down to how your content changes, not whether crawlers can read it.
Reach for SSG when content is stable between deploys: marketing pages, documentation, blog posts, most content sites. You build once, serve static HTML, and get the fastest possible response with content fully present. It’s the strongest, simplest option for anything you want crawled and cited.
Reach for SSR when content is personalized or changes per request: live inventory, prices, dashboards, anything user-specific. You render on demand so each crawler still gets complete HTML, at the cost of running your framework on every request.
For most content that matters to SEO and AI visibility, SSG is the default and SSR is the exception for genuinely dynamic pages. ISR splits the difference, serving static HTML that regenerates on a schedule, and covers a lot of real-world sites well.
When choosing between SSR and SSG, you should understand the difference in their infrastructure profiles. SSG is cheap because pre-built HTML sits on a CDN. SSR pays a compute cost on every request, which adds up at scale. ISR mitigates most of this by regenerating on a schedule and serving cached versions in between. For stable content, SSG wins on both crawler visibility and cost. Factor the infrastructure spend into the SSR-vs-SSG decision.
Rendering is a per-template decision, not a site-wide one
Teams argue about rendering as though the site gets one answer. It doesn’t, and treating it that way is what turns a two-week fix into a six-month migration nobody approves.
Your marketing pages, your product listings, your docs, and your logged-in dashboard have different visibility requirements. Every modern framework lets you set rendering per route. So the question isn’t “should we be SSR or CSR,” it’s “which templates need to be readable without JavaScript,” and the answer is usually a short list.
Work down it in this order:
Is the page behind a login, or app-like? Client-side is fine. Nobody is searching for your settings screen.
Do you want it ranked or cited? It needs content in the raw HTML. Continue.
Does the content change per request or per user? SSR.
Does it change on a schedule rather than per visitor? ISR.
Is it stable between deploys? SSG, and stop there. This covers more pages than teams expect.
A site can run all four at once, and healthy ones usually do.
Links a Crawler Can’t Follow

Rendering gets the attention, and broken links are the failure that quietly costs as much. A crawler discovers your site by following hrefs in the HTML it receives. Anything else is invisible to it.
Three patterns cause this. Navigation built from onclick handlers or <div> and <span> elements styled to look like links gives a crawler nothing to follow, because there’s no href to read. Client-side routing that intercepts navigation and never exposes real URLs has the same effect for anything that doesn’t execute the router. And infinite scroll or “load more” buttons that pull the next batch of items over an API leave everything past the first screen undiscoverable, which is how large catalogs end up with most of their inventory unindexed.
The fixes are unglamorous. Use real <a href="/real-url"> elements for anything you want crawled, including inside JavaScript frameworks, and let the framework improve the click behavior rather than replace the link. Pair infinite scroll with real paginated URLs that work on their own. Make sure every page you care about is reachable from a crawlable link somewhere, not only from a search box or a filtered view.
How to Check What Crawlers See
Before you change any rendering strategy, find out what’s broken. Most of this takes a few minutes and no special tools. Run these checks in order.
View source, not Inspect. Right-click, “View page source.” This shows the raw HTML your server sent, before any JavaScript ran, which is what a non-rendering crawler sees. Search that source for a sentence from your main content. If it’s there, you’re in good shape. If the sentence is missing and you only see an empty <div id="root">, your content is client-side only.
Disable JavaScript in DevTools. Open Chrome DevTools, open the command menu with Ctrl+Shift+P, and run “Disable JavaScript,” then reload. This is a live look at your page with no scripts, close to how a non-rendering crawler experiences it. A blank or skeletal page here is the same warning as an empty pre-render response.
Use Google’s URL Inspection tool. In Search Console, inspect a live URL and look at the rendered HTML and screenshot. This shows Googlebot’s rendered view, so it confirms whether Google can see the content even if AI crawlers can’t. If it's fine here but empty in the raw response, you've found the exact gap this guide is about.
Check your server logs for AI-bot fetches. Look for user agents like GPTBot, ClaudeBot, OAI-SearchBot, and PerplexityBot in your access logs. This tells you which AI crawlers are already hitting your site, and whether they’re getting 200s or 404s. High 404 rates from these bots point at routing or sitemap problems worth fixing.
One process note that saves more trouble than any tool. View Source is an acceptance test, so treat it like one. Add a check to your build pipeline that fetches a few important URLs without a browser and asserts that a known sentence appears in the response body. Rendering regressions ship silently, usually in a release that had nothing to do with content, and a failing build catches them the same day rather than the following quarter.
Rendering Choices that Hold Up in Both Worlds

Once you know what’s missing from the raw HTML, the fixes are less about heroics and more about moving content from “built by JavaScript” to “sent by the server.” Work through these in order.
Put the content that matters in the server HTML. Your headings, body copy, links, and anything you want ranked or cited need to be in the initial response, not injected after load. This is the whole ballgame, and everything else supports it. If the initial HTML response contains your content, most of your JavaScript SEO problem is already gone.
Don’t block JavaScript in robots.txt. Let crawlers fetch your scripts and API responses. Blocking them means Googlebot renders an empty page, and you lose the one crawler that would have executed your code. Serving content in HTML and blocking the JS is the worst of both worlds.
Re-verify with View Source after every change. The framework name on your stack tells you nothing on its own. A “Next.js site” can still ship pages client-side if they’re built wrong. The only proof is what the raw HTML contains, so trust the response body over the docs.
Ecommerce and headless builds deserve a specific warning, because they concentrate the risk in the templates that earn the money. Product listing pages that populate over an API, faceted filters that rewrite results client-side, and price or stock fields injected after load are all common in headless Shopify, Magento, and custom React storefronts, and all of them can leave a category page that looks full to a shopper and empty to a crawler. Prioritize by template rather than by URL: fix the category and product templates first and thousands of pages inherit the fix.
Framework choices that render server-side by default
You don’t have to fight your framework to get server rendering. Pick one built for it and the defaults do the work. Next.js server-renders and statically generates React out of the box. Nuxt does the same for Vue. Remix is server-first by design. And Astro’s Islands architecture ships static HTML by default and hydrates only the interactive components, which is close to ideal for content sites, plenty of HTML, minimal JavaScript.
None of these is a magic fix, and choosing one won’t save you from building pages the wrong way. But starting from an SSR- or SSG-default framework means the easy path is also the crawler-friendly path, instead of the reverse.
Structured data belongs in the HTML, not the JavaScript
If you use JSON-LD structured data, put it in the server-rendered HTML. Schema that’s injected client-side has the same problem as everything else. An AI crawler never runs the code that adds it, so the structured data isn’t there for them. Google can pick up client-side JSON-LD after rendering, but you lose it everywhere else. Render it server-side and every crawler gets it.
A note on performance
Server rendering and payload size are related but separate problems. Moving content into the initial HTML fixes visibility. It doesn’t automatically fix a 2MB JavaScript bundle that blocks interaction, and heavy client-side code still costs you on Largest Contentful Paint and Interaction to Next Paint whether or not the content is server-rendered.
Code splitting, tree shaking, deferring non-essential scripts and trimming third-party tags all help, and they’re worth doing. They’re also a full topic of their own, so treat performance work as the next project rather than a reason to delay the rendering fix. Visibility comes first. A fast page nothing can read is still invisible.
When You Don’t Need to Rebuild for SSR
Now the part that saves money, and it’s less exciting than being told to rewrite everything in Next.js. Plenty of sites don’t have this problem and shouldn’t touch their rendering at all.
If View Source already shows your content, you’re done. A plain HTML site, a WordPress blog, a statically-built marketing site, or a partial-hydration setup where the content ships as HTML and only the widgets hydrate, all of these already serve crawlers what they need. Migrating to SSR would be effort with no upside, and it would add complexity you’d then have to maintain.
Some content genuinely doesn’t need to be crawlable, either. An interactive dashboard behind a login, an internal tool, a checkout flow, a live data visualization nobody searches for, none of these belong in AI answers or organic results anyway. Rendering them server-side for SEO is solving a problem you don’t have. Client-side is often the right call for interactive, gated, or app-like surfaces.
The test is never the framework name and never a blanket rule. It's what the initial HTML response contains on the pages you want found and cited. Run the check first. If the content’s already there, keep your money. If it isn’t, fix those templates, not your entire architecture.
Wrap Up
For years, the argument about JavaScript and SEO was about whether Google could keep up with the frameworks. It could. That debate is over, and the conclusion (ship your React app, Google renders it, everything works) is even true, if Google is the only crawler you care about.
But the bots feeding ChatGPT, Claude, and Perplexity read like it's 2005. They fetch your HTML and leave. Your JavaScript never runs for them, and your Google rankings never say a word about it. That's the uncomfortable part. A whole generation of frontend architecture was built assuming rendering was solved because Google solved it. In 2026, the same architectural choice that got you praised for developer experience is quietly costing you visibility in the fastest-growing discovery channel of the last decade. Server-render the content you want found. The crawlers that can't run JavaScript (most of the ones that matter now — will finally see it.
Frequently Asked Questions
1. How long does it take Google to render JavaScript?
There’s no fixed timeline. Google crawls a page, queues it for rendering, and renders it when capacity allows, which can be minutes, hours, or weeks. High-authority sites crawled often render fast; new or low-authority sites can wait much longer. Server-rendered content skips the wait, because it’s already in the first response.
2. Is JavaScript bad for SEO?
No, JavaScript isn’t bad for SEO on its own. Google renders it reliably. The problem is content that only exists after JavaScript runs, since AI crawlers behind ChatGPT and Perplexity don’t render at all. JavaScript layered on top of server-rendered HTML is fine; JavaScript that is the only source of your content is the risk.
3. Does client-side rendering hurt SEO?
For Google, client-side rendering usually survives but adds rendering delay and fragility. For AI crawlers, it’s worse. GPTBot, ClaudeBot, and PerplexityBot fetch your HTML shell, find an empty content div, and leave without running your JavaScript. A pure client-side page is effectively blank to every AI crawler, so it can rank on Google yet be invisible in AI answers.
4. Can ChatGPT and Perplexity read my website?
They can read whatever is in your raw HTML. Their crawlers fetch and parse HTML but do not execute JavaScript, so any content that only appears after JavaScript runs is invisible to them. If View Source shows your content, they can read it; if it only shows an empty shell, they can’t.
5. SSR vs SSG: which is better for SEO?
Both put content in the HTML crawlers read, so both are strong for SEO. Choose static generation (SSG) for content that’s stable between deploys, like blog posts, docs, and marketing pages, since it’s fastest and simplest. Choose server-side rendering (SSR) for content that changes per request, like live prices or personalized pages.
6. Why do my product pages look empty to crawlers?
Headless and React storefronts often load listings, filters, prices, and stock over an API after the page loads. A shopper sees a full category page while a crawler sees an empty grid. Check View Source on a category and a product URL, then fix those two templates rather than page by page.
Not sure whether your pages are readable to Google and AI crawlers alike? Our technical SEO team runs rendering and crawlability audits that catch exactly this kind of silent visibility gap, then fixes it at the framework and template level. Get in touch and we’ll show you what the crawlers see.
Author

I founded Heroic Rankings with desire to help other businesses increase their visibility and bring real customers. I love SEO and networking with people.