SEO JavaScript
I used to assume Google would render my JavaScript pages correctly if I just waited long enough. A missing title tag in the raw HTML cost me months of ranking.
What I’d do first
- Check titles, meta descriptions, canonical tags and structured data are in the initial HTML, not added by JavaScript.
- Navigation links must be standard <a href="..."> tags so crawlers can follow them without executing scripts.
- Blocking JavaScript or CSS files in robots.txt hurts Google's ability to render your page completely.
- Use server-side rendering or pre-rendering when critical content depends on JavaScript execution.
- Test every page with Google's URL Inspection Tool before launch to confirm what Googlebot actually sees.
The path I'd take
Before anything else, I check what Google actually sees. Open Google Search Console, grab a URL from your site, and run it through the URL Inspection Tool. Look at the 'Page with indexing' section — that's what Googlebot rendered. If the title tag is missing, or the main content is just a loading spinner, you've got a problem that needs fixing at the server level.
Step one: audit your critical SEO elements. Titles, meta descriptions, canonical tags, robots meta tags, hreflang, and structured data must all appear in the initial HTML response. If any of those are injected by JavaScript after the page loads, move them server-side. I have seen sites lose canonical signals because a client-side framework appended the tag 400ms after load — Google may pick it up eventually, but I would not bet on it.
Step two: review your navigation. Every internal link should be a proper <a href="..."> tag with a real URL in the href attribute. No click handlers, no data- attributes that a script walks. [Technical SEO](/technical-seo/) relies on crawlers being able to discover pages without interaction. [Pagination](/pagination/) links are a common place to get this wrong; I have audited sites where "next page" was a JavaScript event that did not generate a URL.
Step three: confirm nothing critical is blocked. Never block JavaScript or CSS files in robots.txt — Google needs those resources to render your page. The same applies to lazy-loading: important above-the-fold content should not be lazy, because early crawl passes might miss it. [Core Web Vitals](/core-web-vitals/) also suffer when rendering is deferred. If your site is a simple blog with minimal JS, you are probably fine. But if your critical content is invisible in the raw HTML, you need to fix that first.
Watch-outs
The most common mistake I see is blocking JS or CSS in robots.txt. It is almost always an accident — someone thought it would speed up crawling, but instead it stops Google from seeing the layout and executing scripts. The result: partial or blank renders. Always allow resources that Google needs.
Second watch-out: JavaScript redirects. Using window.location or history.replaceState for redirects instead of HTTP 301/302 is risky. Google can follow a JS redirect, but it may take longer and the redirect chain is less transparent. For permanent moves, use a [301 Redirect](/301-redirect/) from the server.
Third: hash-based routing. Single-page apps that use # fragments for routing break crawlability because everything after the hash is ignored by the server. Use the History API and real URLs. If you have an existing SPA with hash routes, you are effectively hiding pages from Google unless you have pre-rendering.
Fourth: relying on JavaScript for meta tags. I have seen sites where the <title> is only written by a script after an API call completes. That is a gamble — the initial HTML might contain a generic title or just the app name. [Canonical Tags](/canonical-tags/) are especially fragile; if your canonical is injected client-side and the script fails, you lose control over duplicate content.
Finally, do not lazy-load content that matters for indexing. Lazy loading is fine for decorative images below the fold, but if your main article text or product descriptions are loaded only on scroll, Googlebot may never trigger the scroll event. For SEO-critical content, keep it in the initial DOM or use server-side rendering.
What I got wrong
I used to think that as long as Google could execute JavaScript, I did not need to worry about initial HTML content. I built a single-page app that fetched all content via an API and rendered it client-side. The URL Inspection Tool showed the rendered version after a few seconds, so I assumed everything was fine. But pages took weeks to index, and some never appeared in search results. When I inspected the raw HTML, I found generic titles and missing meta descriptions. Google rendered the page eventually, but the delayed indexing cost me traffic.
Another mistake: I once blocked my JavaScript files in robots.txt because I thought it would reduce crawl budget waste. It did the opposite — Google could not execute the scripts needed to render product pages, so those pages were indexed with empty content. I lost a product category's rankings for two months until I unblocked the files.
I also underestimated how important it is to test on a staging environment. I launched a client's React-based site without checking the raw HTML first. The client's meta descriptions were being injected via an event listener that only fired on user interaction. Google got none of them. Now I always run a pre-launch audit with [SEO Audits](/seo-audits/) that includes checking the initial document.
One thing I still go back and forth on: lazy loading. I know the recommendation is to keep critical content accessible without interaction, but I have worked on sites where lazy loading was the only practical way to keep page weight down for [Website Optimisation](/website-optimization/). In those cases, I compromise by lazy-loading below-fold images but serving the first six items in the initial HTML. It is not perfect, but it has worked for the sites I manage.
Next step
Quick answers
Does Google execute all JavaScript during crawling?
Google executes JavaScript, but it is resource-intensive and can delay indexing. Pages with heavy JS may not be fully rendered on the first crawl pass. Critical content is safer when it is present in the initial HTML response rather than waiting for client-side rendering.
Should I switch my entire site to server-side rendering?
Not necessarily. If your site is informational with minimal JS and your content is already in the HTML, server-side rendering may not be worth the overhead. But if your JavaScript generates titles, links, or content after load, you need either SSR or pre-rendering to make that content reliably crawlable.
How can I test if my JavaScript content is visible to Google?
Use the URL Inspection Tool in Google Search Console. It shows you the rendered HTML that Googlebot sees after executing JavaScript. Compare that against your raw page source. If critical elements are missing or different, you need to adjust your implementation.
Sources
Primary documentation is linked directly. Anything commercial is marked nofollow.
- Google Search Central — Understand JavaScript SEO Basics — Covers how Google handles JavaScript, rendering, redirects, and the core principle of keeping critical signals in the initial HTML.
- Google Search Central — JavaScript SEO guide — Broader documentation on JavaScript crawling, rendering, and indexing issues with implementation patterns.
- Google Search Central — SEO Starter Guide — Foundational principles on crawlable HTML and internal linking that apply to JavaScript-heavy sites.
- Sitebulb — JavaScript SEO — Practical auditing guidance for detecting rendering and crawl issues on JavaScript sites, including lazy loading and navigation patterns.
Notes from Callum Bennett.