JavaScript rendering: what Google sees, what the AI crawlers do not
Google can run your JavaScript, but it does it in a second pass, later and not always. The crawlers behind ChatGPT, Claude and Perplexity do not run it at all. If the words on your page only exist after a script finishes, you are invisible to some readers and late to the rest.
By Théophile Louvart, founder of Porteur · Updated 15 September 2026 · Markdown
The two waves, and why the second one is late
Googlebot fetches your HTML first. It reads what is there, follows the links it finds, and indexes what it can. Anything that only appears after JavaScript runs waits for a second pass, where the page is rendered with an evergreen version of Chromium and read again.
That second pass happens. It is just not on your schedule. A page whose content arrives with the HTML can be indexed the same day; a page whose content arrives after a script may wait, and when rendering fails it is never indexed at all.
- First wave: the raw HTML your server sent. Fast, reliable, read by every crawler on the web.
- Second wave: the rendered page after scripts run. Google only, queued, and dependent on your scripts loading correctly from a data centre.
- No wave: the answering AI crawlers. They read the HTML and stop.
What breaks when the page is built in the browser
Client-side rendering does not fail loudly. The page looks right to you, because your browser ran the scripts. The failures are quiet and they all look the same in Search Console: a page that is crawled and not indexed.
- Links that are not anchors. A div with an onClick handler is a button to a crawler, not a route to another page.
- Content behind an interaction. Text that appears after a click, a scroll handler or a tab change is not seen; content in a collapsed panel that exists in the DOM is fine.
- Routes behind a hash. Anything after the # is not sent to your server and is not treated as a separate page.
- Data fetched on the client. If the product list arrives from an API after load, the first wave sees an empty shell.
- Blocked resources. A robots.txt that disallows your script or style folder stops the render from completing.
- Slow or failing scripts. The renderer gives up; you get the empty shell indexed, or nothing.
<!-- Not a link to a crawler -->
<div class="card" onclick="go('/guides/getting-started')">Getting started</div>
<!-- A link -->
<a href="/guides/getting-started">Getting started</a>How to test what Google actually sees
Do not guess from your own browser. Two checks take five minutes and settle the question for one page.
Look at the HTML your server sends
View source, not the element inspector. The inspector shows the rendered DOM; view-source shows the first wave. Search it for a sentence from the middle of your page. If it is missing, that sentence needs JavaScript to exist.
Inspect the URL in Search Console
Open URL Inspection, run Test live URL, then View tested page. You get the rendered HTML Google produced, a screenshot, and a list of page resources that could not be loaded. Read the resource list first: a blocked script explains most failures.
Check the console messages
The same panel shows JavaScript errors from the render. An error in a data fetch usually means Google saw the empty shell.
Compare the two
If the rendered version holds the content and the source does not, the page depends on rendering. It will be indexed eventually, and it will be invisible to the AI crawlers until you change it.
The four rendering choices, and what each costs
Every framework offers some version of these. The question is not which is fashionable, but where the HTML is assembled.
| Approach | Who assembles the HTML | What a crawler gets on the first fetch | Cost to you |
|---|---|---|---|
| Static generation | Your build | The whole page, instantly | A build step, and a rebuild when content changes |
| Server rendering | Your server, per request | The whole page, at the speed of your server | Server time, and caching to keep the first byte fast |
| Client rendering | The visitor's browser | An empty shell | Invisible to the AI crawlers, late for Google |
| Hybrid | Build or server for the content, browser for the interaction | The whole page, with interactivity added after | The usual answer for a product site |
A worked example. On yourproduct.com, the marketing pages, the guides and the pricing page are static or server rendered, so they exist in the HTML. The dashboard behind the login is client rendered, because no crawler should see it anyway. Nothing is lost and nothing waits for a second pass.
What rendering does to your speed scores
A page built in the browser pays twice: once for the content that arrives late, once for the main thread that is busy while it arrives. Both show up in the numbers Google watches.
- Largest Contentful Paint: the big element cannot paint until the data arrives. Good is up to 2.5 s, poor above 4 s.
- Interaction to Next Paint: hydration blocks the main thread while a visitor is already tapping. Good is up to 200 ms, poor above 500 ms.
- Total Blocking Time: the lab stand-in for the same problem, and the heaviest single item in the Lighthouse performance score.
Server rendering does not fix a heavy bundle. It moves the content earlier, which fixes what a crawler sees and helps the paint. The bundle still has to shrink for the interaction to feel right.
Why the AI crawlers make this urgent
Assistants answer from an index, and the crawlers that build those indexes fetch your HTML without executing it. A page that renders in the browser is not a page they can quote, however well it ranks in Google.
- OAI-SearchBot, for the pages ChatGPT search cites.
- Claude-SearchBot and Claude-User, for Claude.
- PerplexityBot and Perplexity-User, for Perplexity.
- Bingbot, which also feeds Microsoft Copilot.
- Googlebot, which does render, and is the only one of the group that does.
The checklist for a JavaScript site
Move the content to the server
Static or server rendering for every page you want found: the home page, pricing, the guides, the product pages. Keep the browser for what is behind a login.
Make every route a real anchor
Href attributes with real paths, no hash routes for content, no click handlers standing in for links. Your framework's link component does this; a styled div does not.
Unblock your scripts and styles
Check robots.txt does not disallow the folders your page needs to render. Google has said for years that blocking them breaks rendering.
Render the metadata too
Title, description, canonical and structured data belong in the server's HTML. A title written by a script after load is a title Google may never use.
Re-test the page
URL Inspection, Test live URL, View tested page. The content should now be in the source, not only in the render.
Watch the indexing report
Pages stuck on crawled and not indexed often move once the content is in the first wave. Give it a couple of weeks before judging.
A fixed page looks like this: view-source on /pricing shows the plan names, the prices and the FAQ text; the AI crawlers can read it; and the interactive parts, the toggle and the checkout button, still work exactly as before.
Questions
Yes, in a second pass. Googlebot renders pages with an evergreen version of Chromium after the initial HTML crawl. The content is usually indexed, later than HTML content, and not at all if the render fails because a script was blocked or errored.
For pages you want found, yes. Server rendering and static generation put the content in the first fetch, so every crawler sees it, including the AI crawlers that never run JavaScript. Client rendering is fine for anything behind a login.
View the page source and search for a sentence from the body. If it is not there, the page depends on rendering. Then run Test live URL in Search Console and read the blocked resources and console messages on the tested page.
Google no longer recommends dynamic rendering as a long-term answer. Server rendering or static generation solves the same problem without serving two versions of a page, which is harder to maintain and easier to get wrong.
The answering crawlers read the HTML and do not execute scripts, so content that arrives after load is not available to them. If being cited by assistants matters to you, the content has to be in the server's response.
It removes a reason not to rank rather than adding a boost. Pages that were slow to index get indexed sooner, pages that were half read get read fully, and the speed metrics usually improve as a side effect.
Check my site, free
Paste your URL and the free check reads your site the way a crawler does, in about thirty seconds, and says whether your words are in the HTML or waiting on a script.
- Free check, no card
- Read-only, your own accounts
- Readable by your agent
Read next
- GlossaryRendering
- GlossaryJavaScript SEO
- GuideNext.js SEO: what the framework does for you and what it does not
- GuideHow to use the URL Inspection tool in Search Console
- GuideCrawled, currently not indexed: what it means and what to do
- Guiderobots.txt for AI crawlers: GPTBot, ClaudeBot, PerplexityBot and what to allow
- Free toolOn-page SEO checker
- GlossaryKnowledge Graph