
Key takeaways
- Googlebot crawls the raw HTML first, then queues the page for rendering in a headless, evergreen Chromium. Anything that exists only after JavaScript runs depends on that second step working.
- Some signals are read before rendering. A
noindexin the server HTML can stop rendering altogether, and pages with a non-200 status may not be rendered. - Google doesn't keep cookies or local storage between page loads, declines permission requests, follows only
<a href>links and ignores#/fragment routes. - The free rendering lab compares raw and rendered HTML side by side and flags these problems. Confirm what it finds with URL Inspection in Search Console.
When content on a JavaScript site is missing from Google, compare the page's raw HTML with its rendered HTML, then check the rendered version in Search Console's URL Inspection live test. If the content is in neither, the cause is usually a blocked request, an error, or content that needs a click or stored state. If it's only in the rendered HTML, it depends on rendering, so put critical content, titles, canonicals and links in the server HTML.
The JavaScript SEO guide covers rendering strategies and frameworks. This guide is the hands-on debugging part: one script, seven reproducible problems, and a table that matches each symptom to its cause.
How Googlebot renders JavaScript
According to Google's JavaScript SEO documentation, Googlebot works in three phases: crawling, rendering and indexing. It fetches the URL and reads the raw HTML, including links and robots directives. It then puts the page in a render queue, where a headless Chromium runs the JavaScript. Google says a page "may stay on this queue for a few seconds, but it can take longer than that." The rendered HTML is then used for indexing.
Three consequences matter for debugging:
- Some decisions happen before rendering. Google says pages with a 200 status are queued for rendering "unless a robots meta tag or header tells Google not to index the page," and that "if the HTTP status code is non-200 … rendering might be skipped."
- Rendering isn't browsing. Googlebot loads each URL fresh. It doesn't click, log in, accept permission prompts or remember anything from a previous page.
- Other crawlers may never render. Google itself recommends server-side or pre-rendering because "not all bots can run JavaScript."
Step 1: confirm it's a rendering problem
Before blaming JavaScript, check what Google actually has:
- Open URL Inspection in Search Console and enter the URL. If the page isn't indexed, the coverage section explains why. Crawl, canonical and quality problems need different fixes; the discovered vs crawled guide covers those.
- Click Test live URL, then View tested page. The HTML tab shows the rendered HTML, and More info lists page resources that couldn't load and JavaScript console messages.
- Search that rendered HTML for the exact text that's missing, such as a product name, a price or a heading.
If the text is in the rendered HTML, Google can see it, and the problem is elsewhere (indexing, quality or a recent change Google hasn't crawled yet). If it's missing, keep going.
Step 2: compare raw and rendered HTML
URL Inspection checks one page at a time. To check many pages, or to test changes on a staging site, use the rendering lab. Its render_diff.py script fetches the raw HTML, renders the page in headless Chrome or Edge, and compares the two:
python render_diff.py https://example.com/product/honey/ --expect "Himalayan honey 500 g" --expect "NPR 1,250"
For each URL it reports the title, meta robots, canonical, H1, word count, crawlable links, fragment links, clickable elements without an href, structured data types, soft-404 signs, and where each --expect phrase appears: in the raw HTML, only after rendering, or missing. A CSV option checks a list of URLs, each with its own phrases.
Headless Chrome isn't Google's renderer. Timing, caching and blocked resources can differ, so treat the script as a fast first check and confirm important URLs in URL Inspection.
Step 3: match the symptom to the cause
| What you see | Likely cause | Fix |
|---|---|---|
| Content only in the rendered HTML | Client-side rendering | Usually indexable if rendering succeeds. For key pages, server-render or pre-render the main content. |
Page not indexed, but JavaScript removes noindex | Google read noindex in the raw HTML and may have skipped rendering | Don't put noindex in the server HTML of pages you want indexed |
| Title or canonical changes after rendering | Placeholder values in the server HTML | Output the final title, description, canonical and robots tags on the server |
| Linked pages never discovered | onclick navigation or #/ routes | Use <a href="/real-path/"> and the History API |
| Text missing even after rendering | Needs a click, scroll, login, cookie or localStorage value | Render the content by default; don't depend on state from an earlier page |
| "Not found" page returns 200 | SPA catch-all route (soft 404) | Return a real 404, or redirect to a URL that does, or add noindex with JavaScript |
| Console errors or failed resources in URL Inspection | JavaScript error, blocked file or failed API call | Fix the error; don't block JS, CSS or API paths in robots.txt |
| Old content after a deploy | Google cached an old script; it may ignore caching headers | Use fingerprinted file names such as main.2bb85551.js |
| Data never loads | Content arrives over WebSockets or WebRTC | Provide an HTTP fallback; Googlebot only uses HTTP requests |
| Web component content missing | Shadow DOM without <slot> | Use slots for light DOM content, or render the content outside the component |
These causes come from Google's guide to fixing search-related JavaScript problems, which also notes that Googlebot declines permission requests (camera, location) and clears local storage, session storage and cookies between page loads.
What the lab shows
The lab download includes a small practice shop, lab_server.py, with seven problems built in. I ran render_diff.py against it on 3 November 2026 with Chrome's headless mode. The results:
| Lab page | What the script reported |
|---|---|
/static/ | Raw and rendered HTML agree; product name and price in the raw HTML |
/csr/ | 1 word in raw HTML, 24 after rendering; title, H1, price and 2 links exist only after rendering |
/noindex-flip/ | noindex in the raw HTML, removed by JavaScript: Google may never render it |
/title-swap/ | Title "Loading…" and a homepage canonical in the raw HTML, corrected only by JavaScript |
/js-links/ | 2 clickable elements without href and 2 #/ fragment links; no crawlable links |
/stored-city/ | Expected delivery text missing even after rendering: it needs a value saved on an earlier visit |
/product/does-not-exist | "Product not found" with HTTP 200: soft 404 |
For comparison, I ran the same script on this site's JavaScript SEO guide, a static page. Raw and rendered HTML matched: 3,372 words and 74 crawlable links in both. The full output for every page is in the results file (JSON).
Step 4: fix it and verify
Most fixes come down to one principle: anything Google must read, put in the server HTML.
- Server-render or pre-render important pages so the main content, title, canonical, robots tag and links are in the first response. The JavaScript SEO guide compares rendering strategies, and the Next.js streaming metadata guide covers a common framework case.
- Return real status codes for missing pages. The React SPA SEO audit and Next.js 404 guide walk through it.
- Use real links with
hrefattributes for every page you want crawled. - Log JavaScript errors from real visitors, including Googlebot. Google's documentation includes a
window.onerrorexample that reports errors to your server.
After deploying a fix, re-run render_diff.py on the same URLs, then run a URL Inspection live test on a few of them and request indexing. Google says to test again with URL Inspection or the Rich Results Test once you've worked through the checklist.
Frequently asked questions
Does Google index JavaScript content?
Yes. Google renders pages with a headless, evergreen Chromium and indexes the rendered HTML. Rendering can be delayed, may be skipped for noindex or non-200 pages, and depends on the JavaScript running without errors, so critical content is safest in the server HTML.
How long does Google take to render a page?
Google says a page may wait in the render queue for a few seconds, but it can take longer. Don't rely on content that only appears after long delays or user interaction.
Is headless Chrome the same as Googlebot?
No. Headless Chrome is a useful approximation, but Google's renderer has its own caching, resource limits and behaviour. Use a local comparison to find likely problems, then confirm them with URL Inspection's live test.
Do other search engines and AI crawlers render JavaScript?
Not reliably. Google notes that not all bots can run JavaScript. If you want a page understood by every crawler, put its main content, metadata and links in the server HTML.
Sources and further reading
Is a JavaScript site missing from Google? See my technical SEO service.
Get in touch