JavaScript SEO is making sure search engines and AI crawlers can crawl, render and index pages built with React, Next.js, Angular or Vue. Google runs your JavaScript before it indexes a page. ChatGPT, Claude and Perplexity's crawlers don't. So content that appears only after the browser runs your code can rank in Google and still be invisible to AI answers. The fix has two parts. Send the content, title, canonical, links and structured data in the first HTML response, and test every template on every release.
I'm Brenden House. I run Searchmaxxed, an SEO and AI SEO agency. Our own site is a React app, so we deal with this every week. It's written for marketing and engineering leads on large JavaScript sites, the people who have to agree on how pages get built and tested. It covers the rendering choice, what each crawler sees, testing at scale and governance. I checked every source on 27 October 2026 (AEST).
In summary
- Google renders JavaScript. Most AI crawlers don't. In Vercel and MERJ's 2024 tests, GPTBot, OAI-SearchBot, ClaudeBot and PerplexityBot read pages without running scripts.
- Raw HTML is the safe contract. Server-side rendering or static generation puts the full page in the first response.
- Diff raw and rendered HTML per template. A canonical, title or noindex that changes between the two is the classic silent failure.
- Next.js has a newer trap. Streamed metadata lands in the page body for any bot missing from its "HTML-limited" list, and that default list names no AI crawler.
- Build checks beat audits. Put the tests in the pipeline.
| Crawler | Runs JavaScript? | What it reads |
|---|---|---|
| Googlebot (Search, AI Overviews, AI Mode) | Yes | Rendered HTML |
| Gemini | Yes, through Google's infrastructure | Rendered HTML |
| Applebot | Yes | Rendered HTML |
| GPTBot, OAI-SearchBot, ChatGPT-User | No | Raw HTML |
| ClaudeBot | No | Raw HTML |
| PerplexityBot | No | Raw HTML |
| CCBot (Common Crawl) | No | Raw HTML |
Source: Vercel and MERJ, "The rise of the AI crawler", 2024. Microsoft Copilot wasn't tested. It has no separate user agent.
What is JavaScript SEO?
JavaScript SEO is the part of technical SEO that deals with pages whose content, links or tags depend on JavaScript. It matters most on single-page apps and on sites built with React, Next.js, Angular, Vue or Nuxt. Plain HTML sites barely need it.
Five terms carry most of the subject:
- Raw HTML (or response HTML) is what the server sends before any script runs, the thing you see in "view source".
- Rendered HTML is the page after the browser runs the JavaScript and builds the DOM. Chrome DevTools shows it in the Elements panel.
- Client-side rendering (CSR): the server sends an empty shell and the browser builds the page.
- Server-side rendering (SSR) builds the full HTML on the server for each request, while static site generation (SSG) does it once at build time.
- Hydration attaches JavaScript to HTML the server already sent, which is how a server-rendered page becomes interactive.
Everything hangs on the gap between raw and rendered HTML. Google indexes the rendered version. AI crawlers mostly read the raw one. When the two disagree, you're effectively publishing two different websites, one for Google and one for every AI crawler.
How does Google crawl, render and index JavaScript?
Google handles JavaScript in three phases: crawl, render, index. Googlebot fetches the URL and queues it. Later, Google's Web Rendering Service (WRS), a headless Chromium, runs the JavaScript. Then Google indexes the result.
Google's JavaScript SEO guide, last updated 4 March 2026, sets the hard rules:
- Only
200pages get rendered. - Google won't render a page, or its scripts, if robots.txt blocks them.
- Links count only as
<a>elements with anhref, so route with the History API, never#/fragments. - Don't use JavaScript to change the canonical to a different URL from the raw HTML.
- Client-side routes can't send a real 404 status. Redirect to a URL that returns one, or add
noindex.
How long does rendering wait? Vercel and MERJ matched more than 37,000 Googlebot crawls on nextjs.org against finished renders, and their 2024 study found a median delay of 10 seconds. The 90th percentile was about 3 hours. The 99th: about 18 hours.
Keep in mind that nextjs.org is one fast, heavily linked site, run by the people who build the framework. On an estate with a million product URLs, crawl budget and server speed stretch every number. Another finding bites large sites hard. A noindex in the raw HTML stops the render, so JavaScript that removes it never runs.
Can ChatGPT, Claude and Perplexity see JavaScript content?
Mostly not. In Vercel and MERJ's tests, OpenAI's crawlers, ClaudeBot, PerplexityBot, Meta's crawler and Bytespider fetched JavaScript files without executing them. Browser-built content never reached them.
Gemini is the exception, because it runs on Googlebot's infrastructure. Applebot renders too. Google's AI Overviews and AI Mode link to pages in Google's own index, which is built from rendered HTML.
Picture a B2B SaaS company that loads its pricing table from an API after the page opens. Google indexes the plans. Someone asks ChatGPT what the product costs, and its crawler finds an empty <div>. The answer has to come from somewhere else, like a review site's old numbers.
A caveat. Those tests date from 2024, and AI companies change crawlers without announcing it. Don't trust any blog post on this, ours included, when your server logs can show you exactly what each bot fetched last week.
Which rendering method should an enterprise site use?
Static generation or server-side rendering for every page you want found, and client-side rendering only behind a login. That one rule settles most arguments between marketing and engineering. Why? Every crawler then gets the same complete HTML.
| Method | What Google sees | What AI crawlers see | Best for | Watch out for |
|---|---|---|---|---|
| Static generation (SSG) | Full page | Full page | Marketing pages, docs, blog, research | Long builds on huge sites |
| Incremental static regeneration (ISR) | Full page | Full page | Large catalogues that change daily | Stale pages if revalidation fails |
| Server-side rendering (SSR) | Full page | Full page | Inventory, prices, personalised listings | Server load and slow time to first byte |
| Streaming SSR (React Server Components) | Full page | Body yes; check where metadata lands | Next.js App Router sites | Metadata streamed into the body |
| Client-side rendering (CSR) | Usually, after the render queue | An empty shell | Logged-in apps, dashboards | Everything in this article |
| Dynamic rendering | A prerendered copy | A prerendered copy, if the bot list is right | Legacy SPAs you can't rebuild yet | Google calls it a workaround |
Vercel and MERJ rated SSG and ISR "excellent" for crawl efficiency, SSR "very good" and CSR "poor". Google is blunter about dynamic rendering. Its own page calls it "a workaround and not a recommended solution".
Choose per page type. A manufacturer might serve 40,000 product pages with ISR, spec sheets as static files and the distributor portal with CSR behind a login. Only the first two need to rank.
What changes for React SEO?
Plain React renders in the browser. A Create React App or plain Vite build sends an empty <div id="root"> plus a script tag. Google will usually render that. AI crawlers see nothing.
There are three ways out, listed from the smallest change to the largest:
- Prerender at build time. Render every public route to static HTML and hydrate it in the browser.
- Move to a framework with SSR, such as Next.js, React Router (formerly Remix) or Astro.
- Use a prerender service that serves crawlers a rendered copy. That's dynamic rendering, so treat it as a bridge.
React Helmet and similar libraries set the title and meta tags with JavaScript. Google renders first, so it reads them fine. In a client-rendered app those tags are missing from the raw HTML. AI crawlers miss them, and so do LinkedIn and Slack link previews. React 19 can render <title> and <meta> from inside components, but that only reaches the raw HTML when the server does the rendering.
Our own site takes the first route. Searchmaxxed.com is a React 19 app built with Vite, and every public route renders to static HTML at build time. Research articles and service pages ship with no application JavaScript at all. Only pages that need it hydrate, like the homepage and the contact form.
What should you check on a Next.js site?
Next.js renders on the server by default. Most Next.js sites start in good shape, and the problems come from how teams use it. Six checks:
- Data fetched in client components. Content loaded in a
useEffectinside a'use client'component is client-side rendering, invisible to AI crawlers. - Streaming metadata. When
generateMetadatawaits on data, Next.js can send the page first and append the title and meta tags to the<body>afterwards. Its docs say bots on an "HTML-limited" list get a blocking render with the tags in the<head>. - Who's on that list. I read the default list in the Next.js source on 27 October 2026. Bingbot, Applebot and LinkedInBot are on it. GPTBot, OAI-SearchBot, ClaudeBot and PerplexityBot aren't.
- Real links.
next/linkrenders an<a href>, while anonClickon a button or div gives crawlers nothing to follow. - Status codes. Call
notFound()for missing records, so a deleted product returns a 404 instead of an empty page with a 200 status. - Sitemaps and robots. Generate
sitemap.tsfrom the same data as your routes, and never block/_next/assets in robots.txt.
What does point 3 mean? On dynamic routes, AI crawlers may find your title and description in the body. I haven't tested whether each one reads them there. If it matters to you, add those bots to htmlLimitedBots in your config, then check the raw HTML they get. Next.js warns that overriding the list can slow responses. Measure that too.
What breaks most often on large JavaScript sites?
The silent failures cost most. The page looks perfect in a browser while telling crawlers something else, and nobody notices until traffic or AI citations drop. Here's how to catch each.
| Failure | What crawlers get | How to find it | Fix |
|---|---|---|---|
| Body content built in the browser | Empty shell for AI crawlers | Raw HTML has no main text | SSR or SSG for that template |
| Canonical or title rewritten by JavaScript | Two different signals | Raw vs rendered diff | Set it once, on the server |
noindex in raw HTML, removed by JavaScript | Page dropped | Raw HTML check per template | Remove it on the server |
| Soft 404s on client-side routes | Empty 200 pages indexed | Search Console "Soft 404" report | Real 404 status or noindex |
Links as onClick or # fragments | Pages never discovered | Crawl with JavaScript off | <a href> with real paths |
| Infinite scroll with no page URLs | Only the first batch indexed | Rendered HTML stops at item 20 | Paginated URLs linked in HTML |
| Lazy-loaded content that waits for a scroll | Blank sections | Rendered screenshot in URL Inspection | Show it in the first render |
| JSON-LD added in the browser | No schema for AI crawlers | Raw HTML has no application/ld+json | Render schema on the server |
| robots.txt blocking scripts or APIs | Page can't render | URL Inspection "page resources" | Allow the assets Google needs |
| Old bundles cached by Google | Stale or broken render | Rendered HTML differs from live | Fingerprinted file names |
Two rows are our own scars. Our build now fails if a scroll animation fades content in from zero opacity, since a renderer that never scrolls would see blank space. It also fails when a page's HTML holds no real text. An earlier build passed while shipping empty shells.
How do you run a JavaScript SEO audit at scale?
Audit by template, not by URL. A site with two million pages might run on 30 templates, and every page on a template fails the same way. So sample each template, compare what each crawler gets, then fix the template once.
- List your templates. Group URLs by page type (product, category, article, location, comparison, search results) and note each one's rendering method.
- Sample. Take 10 to 20 URLs per template: the oldest, the newest, the biggest. Edge cases break first.
- Crawl twice. Run Screaming Frog, Sitebulb or a similar crawler with JavaScript off, then on. Diff the title, description, canonical, robots tag, H1, word count, links and structured data.
- Fetch as the AI crawlers. Request each sample with the GPTBot, ClaudeBot and PerplexityBot user agents, scripts off. No main text, no AI citation.
- Check Google's view. URL Inspection in Search Console shows the rendered HTML, a screenshot and blocked resources. The URL Inspection API allows 2,000 inspections a day per property, plenty for every template's sample.
- Read the logs. They show which bots fetched which URLs and what status each got.
- Measure speed per template. Core Web Vitals field data (LCP, INP and CLS) by page group shows where heavy hydration hurts, usually as a poor INP.
- Rank the fixes. Weigh each fault by the pages and revenue on its template. A broken canonical on the product template beats 400 warnings on the blog.
Our SEO audits work the same way. Faults are ranked by what they cost, traced to templates and handed over as fixes your engineers can merge.
How do you stop JavaScript SEO regressions after launch?
Put the checks in the build pipeline. A release that breaks a template should fail before any crawler sees it, rather than surface in a quarterly audit months after the traffic went.
Our own site is the working example. Searchmaxxed.com renders every route to HTML, then a verify script reads the output and fails the deploy on any of these:
- No title or canonical, or more than one
- A rendered title or description that differs from the source data
- An
og:urlthat doesn't match the canonical - Zero H1s, or several
- A page with no real text in its HTML
- Missing or malformed JSON-LD, or FAQ schema that doesn't match the visible FAQ on the page
- Internal links to missing pages or redirects
- A sitemap that isn't exactly the set of indexable pages
- A robots.txt missing a named AI crawler, such as GPTBot, ClaudeBot or PerplexityBot
Why does it exist? The opening comment says it plainly. "Every structural check below is a defect that actually shipped." That's governance on a JavaScript site. Each failure becomes a test, so the same defect fails the build next time.
Write down who owns what, too. JavaScript SEO sits between two teams, and unowned work waits.
| Decision | Engineering | Marketing or SEO |
|---|---|---|
| Rendering method per template | Owns | Signs off for public templates |
| Title, meta, canonical and schema rules | Builds | Owns the rules |
| Build checks for SEO | Owns the pipeline | Writes the checks |
| New page types and URL patterns | Builds | Approves before launch |
| Monitoring logs, Search Console and AI crawlers | Supports | Owns |
| Framework upgrades | Owns | Tests the sample set before release |
Watch the last row. A framework upgrade can change where metadata renders, as Next.js streaming did. Run the sample-URL test against every upgrade's preview build.
How does Searchmaxxed handle JavaScript SEO?
Searchmaxxed does technical SEO, AI SEO, GEO and AEO for enterprise, B2B SaaS, venture-backed, manufacturing and public-sector companies. On a JavaScript site we find what each crawler can't see, deliver the fix ready to merge and add the checks that keep it fixed. Our technical SEO service covers rendering, crawling, indexing, speed and schema.
Here's how the work runs. AI agents pull your Search Console and GA4 data, read the Google results and check what AI answers say about you. That feeds the Managed Search Loop. It shows which template fix or page should bring the most enquiries next. We deliver each change ready to merge, sized for your release process, then check the live page and measure what moved. You own the site, repository, content and data from day one.
| Package | Who it suits | What it means for a JavaScript site |
|---|---|---|
| Growth System | A company growing in one or two markets | Technical, schema and internal-link work alongside 30 page releases a month |
| Agentic Search Engineering | A competitive or national category | Everything in Growth System, 50 page releases a month, and AI answer tracking across ChatGPT, Gemini, Perplexity and AI Overviews |
| Custom & Enterprise | Several brands, markets or a very large estate | Scope can include dedicated engineering, several markets and custom reporting |
Is the platform itself the blocker? Our Agentic Migration keeps a design worth keeping and moves the site onto infrastructure built for ongoing search work. For estates with several teams and a long release queue, see enterprise SEO. AI answers the bigger gap? Start with AI search optimisation.
Searchmaxxed's work has generated more than A$10 million in revenue through search for its clients.
Is Searchmaxxed right for you?
We suit marketing and engineering leads who want JavaScript SEO fixed in the code, not described in a deck. Want a one-off report, or have no way to ship changes? Wrong call.
| Searchmaxxed is a good fit if | Look elsewhere if |
|---|---|
| Your site runs on React, Next.js, Angular, Vue or Nuxt and public pages matter to pipeline | Your public site is plain HTML or a hosted CMS with no rendering issues |
| You want fixes delivered ready to merge, with checks added to the build | You only want an audit document to hand to another team |
| You care about AI answers as well as Google rankings | Google is your only concern and your rendering already passes |
| Your engineers are stretched and SEO tickets wait months | You have spare engineering capacity and an in-house technical SEO |
| You want to own the site, repository, content and data | You want an agency to host and control your site |
In the right-hand column? A crawler licence and your own team will serve you better.
Frequently asked questions
Is JavaScript bad for SEO?
No. JavaScript is fine when the content, links and tags are already in the HTML the server sends. It hurts when the page exists only after scripts run. AI crawlers won't see it.
Does Google index JavaScript content?
Yes. Googlebot renders pages in a headless Chromium and indexes the rendered HTML. Vercel and MERJ's 2024 study measured a median render delay of 10 seconds on nextjs.org, with the 99th percentile at about 18 hours.
Do AI crawlers render JavaScript?
Most don't. In Vercel and MERJ's 2024 tests, OpenAI's crawlers, ClaudeBot and PerplexityBot didn't execute JavaScript, while Gemini and Applebot did. Crawlers change, so check your logs.
Is React bad for SEO?
React isn't. Client-side rendering is the risk. A React app that renders on the server, or prerenders at build time, sends full HTML. A plain single-page React app sends an empty shell that only Google reliably renders.
Is Next.js good for SEO?
Yes, by default. It renders on the server and ships a Metadata API. Watch two things: content fetched in client components, and streamed metadata on dynamic routes.
Is dynamic rendering still OK?
Only as a bridge. Google calls it "a workaround and not a recommended solution". SSR or static generation is the real fix.
How do I check what Google sees on my page?
Open Search Console's URL Inspection tool and view the rendered HTML and screenshot. For any public URL, the Rich Results Test shows the same rendered view, and comparing it with "view source" exposes what JavaScript changed.
What should you do next?
Pick your most valuable template. Fetch one of its pages with JavaScript off and look for the main text, title, canonical and schema. Anything missing is invisible to AI answers. If you'd like us to run that test across every template and fix what we find, let's talk pricing.