In this article
JavaScript SEO comes down to one rule. Make sure the content, links and metadata you want indexed exist in the HTML a crawler can actually read, ideally before any script runs. Google can render JavaScript, but it does so later, with limits, and other bots often don't render it at all. That gap between what your browser shows and what a crawler receives is where rankings disappear. This piece explains how rendering works, the pitfalls that quietly break indexing, and the rendering strategies that keep dynamic pages visible.
How Does Google Render JavaScript Pages?
Google processes JavaScript pages in three stages: crawling, rendering and indexing. Googlebot first fetches the raw HTML and pulls out any links it finds. The page then waits in a render queue until a headless, evergreen version of Chromium executes the scripts. Only the rendered output is fully indexed, so anything that fails to render is invisible.
That evergreen detail matters. Since May 2019, Googlebot has run a current version of Chromium, so modern syntax, ES modules and most web APIs work. Old advice about transpiling everything down to ES5 for Google's sake is outdated.
What hasn't changed is the two-step nature of the process. The first pass sees only the server response. If your initial HTML is an empty <div id="root"></div> and a bundle file, Google learns almost nothing until rendering happens. Google's own engineers, including Martin Splitt, have said the median wait in the render queue is short, often seconds. The long tail is the problem. Large sites with thousands of new URLs can see rendering lag behind crawling, and new content takes longer to surface.
The renderer also behaves differently from a real visitor. It doesn't click, scroll like a person, accept cookie banners, or grant permissions such as geolocation. It is stateless, so local storage and cookies are wiped between page loads. And it won't wait forever for slow API calls. If your product grid depends on a request that takes eight seconds, assume Google may index the page without it.
So the mental model is simple. Treat rendering as a helpful fallback, not a guarantee.
Why Dynamic Content Still Goes Missing
Plenty of teams assume that because Google renders JavaScript, they're safe. Then a site migration to a single-page application drops organic traffic by a third, and nobody can explain why. I've seen that exact pattern more than once, and it's rarely one dramatic bug. It's usually a stack of small ones.
Rendering costs Google far more resources than parsing static HTML. Every script, font and API call has to be fetched and executed. On large sites, that cost interacts with crawl budget: if Googlebot spends time fetching dozens of JavaScript chunks per page, it may crawl fewer pages overall. Ecommerce catalogs and news sites feel this most.
Timing is the second factor. A news article that renders its body client-side might be crawled within minutes of publishing, but the text only becomes indexable after rendering. For time-sensitive content, that delay is a real competitive disadvantage.
Then there are failures that never show up in your browser:
- Script errors triggered by missing browser features or blocked third-party resources.
- API endpoints blocked in robots.txt, so the page loads but its data never arrives.
- Timeouts on slow backends, especially under heavy crawl load.
- Geo or consent walls that hide content from a crawler requesting from US data centers.
Here's the gotcha that catches experienced developers. Someone adds Disallow: /api/ to robots.txt to "save crawl budget." Googlebot obeys, the renderer can't fetch the JSON that fills the page, and every product description quietly vanishes from the index. The page looks perfect to every human who checks it.
Common JavaScript SEO Pitfalls to Fix First
Most indexing problems on dynamic sites trace back to a handful of recurring mistakes. Audit these before anything else.
Links that aren't really links
Google discovers URLs through <a> elements with an href attribute. A <span onclick="goTo('/shoes')"> or a button that pushes a route is not a link to a crawler. Neither is href="javascript:void(0)". Use real anchor tags with resolvable URLs, then let your router intercept the click.
Hash-based routing
URLs like example.com/#/pricing are treated as the same page as the homepage, because Google generally ignores fragments. Switch to the History API so each view has a clean path.
Soft 404s in single-page apps
An SPA often returns a 200 status for every URL, then displays a "not found" message client-side. Google may index those as thin pages or flag them as soft 404s. Fix it by returning a real 404 from the server, or by redirecting to a URL that does return one, or by injecting noindex on error views.
Metadata changed after load
Titles, meta descriptions and canonical tags rewritten by JavaScript can work, but they add risk. Conflicting signals between raw and rendered HTML are a classic cause of the wrong canonical being chosen. Serve the correct values in the initial response.
The noindex trap
This one deserves bold type. If the initial HTML contains noindex, Google may skip rendering entirely, so removing the tag with JavaScript does nothing. Teams use this pattern for "loading" states and wonder why pages never index.
Content hidden behind interaction
Tabs are usually fine if the content sits in the DOM. Content fetched only after a click, a "load more" button or a scroll event often isn't. For infinite scroll, provide paginated URLs with real links. For lazy-loaded images, use native loading="lazy" or IntersectionObserver rather than scroll listeners. Our guide to image SEO for search and AI results covers the visual side in more detail.
Rendering Strategies Compared
How your pages get built determines how much of this risk you carry. There are five main approaches, and they aren't equal.
Client-side rendering (CSR)
The server sends a minimal shell and the browser builds everything. It's the default for many React or Vue setups created without a framework. CSR is cheap to host and fine for logged-in dashboards. For public pages that need search traffic, it's the weakest choice, because every bit of content depends on the render queue.
Server-side rendering (SSR)
The server runs the JavaScript for each request and returns complete HTML, which then hydrates in the browser. Next.js, Nuxt, SvelteKit and Remix all support this. Crawlers get full content on the first pass. The trade-off is server cost and complexity, plus a need to watch time to first byte.
Static site generation (SSG)
Pages are rendered to HTML at build time and served from a CDN. Astro, Next.js and Gatsby-style builds do this well. It's fast, robust and nearly impossible for a crawler to misread. The catch is freshness: a catalog of 200,000 products can't be rebuilt every few minutes.
Incremental static regeneration and hybrids
ISR in Next.js, and similar features elsewhere, regenerate static pages on a schedule or on demand. You get static speed with near-real-time updates. For most marketing sites and large catalogs, a hybrid of static and server rendering per route is the sweet spot.
Dynamic rendering
This serves pre-rendered HTML to bots and the normal app to users, often through tools like Rendertron or Prerender.io. Google now describes it as a workaround rather than a recommended long-term solution. It also creates two versions of every page to maintain, and those versions drift apart.
Which Rendering Strategy Should You Choose?
For public pages that need organic traffic, choose server-side rendering or static generation, usually through a framework like Next.js, Nuxt or Astro. Use static generation wherever content changes infrequently, SSR where it changes per request, and keep pure client-side rendering for authenticated areas. Avoid dynamic rendering unless you're stuck with a legacy app.
That's my firm recommendation, and here's the reasoning. SSR and SSG remove the dependency on the render queue for the things that matter: main content, internal links, titles, canonicals and structured data. Interactivity can still load afterward. You stop hoping Google renders correctly and start guaranteeing it.
A practical split for a typical B2B site might look like this:
- Blog, docs and landing pages: static generation with on-demand revalidation.
- Product and pricing pages: SSR or ISR so prices and stock stay accurate.
- Search results and filters: SSR for indexable combinations, noindex for the rest.
- Account area: client-side rendering, blocked from indexing.
One caution about hydration. A server-rendered page that throws hydration errors can flash, re-render or wipe content in the browser. Users notice, and Core Web Vitals such as Interaction to Next Paint suffer. Keep server and client output identical, and watch the console for hydration warnings during QA.
Rebuilding an entire app isn't always possible, of course. If you're stuck with CSR, prioritize pre-rendering your highest-value templates first rather than waiting for a perfect migration.
How to Test What Search Engines Actually See
Never trust what your own browser shows. Test the raw response and the rendered result separately, then compare them.
- View source versus Inspect. Right-click and choose View Page Source to see the raw HTML. Inspect Element shows the rendered DOM. If your main copy appears only in the second, you depend on rendering.
- Disable JavaScript. In Chrome DevTools, open the command menu with Ctrl+Shift+P and type "Disable JavaScript." Reload. Whatever remains is your safety net.
- URL Inspection in Search Console. Run a live test, then open "View tested page" to see rendered HTML, a screenshot and JavaScript console messages. Check the indexed version too, since the live test and the stored crawl can differ.
- Rich Results Test. Useful for confirming that structured data injected by scripts is detected.
- Crawlers with rendering. Screaming Frog and Sitebulb can crawl in rendering mode and compare raw against rendered HTML at scale.
A time-saver few people know about: Screaming Frog defaults to text-only crawling. You have to switch it under Configuration, then Spider, then Rendering, and choose JavaScript. Enable the option to store both raw and rendered HTML, and the tool will highlight pages where word count or links change after rendering. That single report often exposes a broken template in minutes.
Also check server logs. If Googlebot requests your HTML but rarely fetches your JavaScript bundles or API endpoints, something is blocking the renderer. For ongoing checks on the content itself, our roundup of SEO content optimization tools lists options that fit into a regular audit routine.
AI Crawlers and Bots Beyond Google
Google isn't your only audience anymore. Bing renders JavaScript, though it has long encouraged sites to reduce reliance on it. Social preview bots from Facebook, LinkedIn and Slack generally read only the raw HTML, which is why client-rendered Open Graph tags so often produce blank link previews.
AI crawlers raise the stakes further. Research published by Vercel and MERJ in late 2024 found that major AI crawlers, including OpenAI's GPTBot and Anthropic's ClaudeBot, fetched JavaScript files but did not execute them. In practice, a client-rendered page may look empty to the systems that power AI answers and citations.
Think about what that means for a SaaS company whose comparison pages are built entirely in React. Google might rank them. ChatGPT and Perplexity may never see a word of them. If visibility in AI-generated answers matters to your brand, server-rendered HTML is no longer optional.
Clean markup helps here too. Logical headings, descriptive paragraphs and lists are easier for any parser to extract. Our article on how SEO content structure improves readability explains the principles that make pages easy for both people and machines to digest.
A Practical JavaScript SEO Checklist
Use this list during audits, pre-launch QA and framework migrations. Each item is quick to verify.
- Primary content appears in the raw HTML response, not only after scripts run.
- Title, meta description, canonical and robots tags are correct in the initial HTML.
- No noindex in the initial response for pages meant to rank.
- All internal navigation uses <a href> with clean, fragment-free URLs.
- Missing pages return a real 404 or 410 status code.
- robots.txt does not block JavaScript, CSS or the API endpoints that supply page content.
- Infinite scroll has paginated, linkable fallbacks.
- Structured data validates in the Rich Results Test.
- Open Graph tags exist in raw HTML for social previews.
- Rendered and raw word counts match closely in a rendering crawl.
- Hydration errors are cleared from the browser console.
Run the checklist on templates, not individual URLs. One product template fix can repair ten thousand pages at once. And pair technical fixes with solid planning: rendering solves visibility, but you still need pages people actually search for, which is where disciplined SEO keyword research comes in.
Frequently Asked Questions
Does Google index JavaScript content as well as static HTML?
Google can index JavaScript content, but not always as quickly or reliably as static HTML. Rendered pages wait in a queue, scripts can fail or time out, and resources blocked by robots.txt never load. Content present in the initial server response is indexed on the first pass, which is why server-side rendering or static generation remains the safer choice for important pages.
Is dynamic rendering still a good JavaScript SEO solution in 2026?
Dynamic rendering still works, but Google treats it as a temporary workaround rather than a recommended approach. It doubles maintenance, because bots and users receive different versions that can drift apart. If you're starting a new project or planning a rebuild, choose server-side rendering, static generation or a hybrid framework instead. Reserve dynamic rendering for legacy apps you can't refactor soon.
How can I tell if my JavaScript site has indexing problems?
Compare raw and rendered HTML. Run Search Console's URL Inspection live test and review the rendered HTML and console errors. Crawl the site in JavaScript rendering mode with Screaming Frog or Sitebulb and look for pages where word count or link totals jump after rendering. A rising number of "Crawled, currently not indexed" URLs is another warning sign.
Do AI search tools like ChatGPT read client-side rendered pages?
Often they don't. Research by Vercel and MERJ found that major AI crawlers such as GPTBot and ClaudeBot downloaded JavaScript files without executing them. That means content built only in the browser may be invisible to them. Serving complete HTML from the server is the most dependable way to make your pages readable and citable by AI-driven search tools.
Dynamic sites and strong search visibility aren't at odds. The fix is architectural: put your content, links and metadata in the HTML that leaves the server, and let JavaScript add interactivity on top. Audit raw versus rendered output, clear the common pitfalls, and choose SSR or static generation for anything that needs to rank. Do that, and Google, Bing and AI crawlers will all see the same page your visitors do.
