JavaScript SEO: Why Google Cannot See Your Content
The page works perfectly in Chrome, yet Google indexes an empty title and a few footer lines. Engineering says modern crawlers execute JavaScript; the SEO team sees URLs that never gain visibility. Both sides are only half right.
Google can render JavaScript, but that does not mean every JavaScript application is crawled quickly, understood correctly, and indexed completely. Diagnose the page through the three stages Google actually uses: crawl the HTML, render the JavaScript, and index the result.
How Google processes JavaScript pages
Stage 1: Crawling
Googlebot fetches the URL and reads the HTTP status, headers, robots directives, and initial HTML. It can already extract <a> links, canonicals, titles, and content present in the response.
If the server returns 404, 500, blocks crawling, or sends noindex, processing may stop before the application runs.
Stage 2: Rendering
A 200 page can enter a rendering queue. A headless version of Chromium runs JavaScript, fetches allowed resources, and creates the rendered DOM. Waiting time varies with crawler resources.
Stage 3: Indexing
Google reads content and links from the rendered HTML, then evaluates canonicals, quality, duplication, and indexability. Successful rendering still does not guarantee indexing; the page must provide value and coherent signals.
The fastest test: disable JavaScript
Use View Source or curl to inspect the HTML response. Do not rely only on DevTools Elements, which shows the DOM after scripts have run.
Look for five items:
- Are the title and meta description present?
- Is the H1 and primary copy visible?
- Are internal paths real
<a href>links? - Are canonical and robots tags correct immediately?
- Does the server return the right status?
If the response contains only <div id="app"></div>, discovery depends on rendering. That is not automatically broken, but it makes indexing and debugging slower than necessary.
Seven common JavaScript SEO failures
1. Content appears only after user interaction
Googlebot is not required to click tabs, expand accordions, operate infinite scroll, or press “Load more.” Content fetched after an action may never be discovered.
Render important content in HTML or provide a distinct URL and crawlable link for each state that deserves indexing. An accordion whose content already exists in the DOM is safer than one that fetches only after a click.
2. Client routes always return 200
A SPA may display “Not found” while the server returns 200, creating a soft 404. The opposite also occurs: a valid route receives a server 404 before the frontend router starts.
Every indexable URL needs a meaningful server status. Missing pages return 404; moved content redirects; temporary application failures return 5xx.
3. Links cannot be crawled
This looks like navigation to a user but is not a reliable crawl path:
<span onclick="goTo('/products')">Products</span>
Use:
<a href="/products">Products</a>
A client router can still intercept navigation as long as the anchor contains a real URL.
4. JavaScript rewrites the canonical
The canonical should be present in source HTML and remain stable. If source points to URL A and a script changes it to B, the crawler receives conflicting signals at different stages. Likewise, do not expect JavaScript to remove noindex; Google may see the directive and skip rendering.
5. Robots rules block bundles or APIs
The application may need JavaScript, CSS, or a public API to construct content. When Googlebot cannot load those resources, rendering can be blank or incomplete.
Private APIs still require protection. Public data necessary to render an indexable page needs an explicit crawler-access strategy.
6. Rendering depends on local storage, cookies, or location
Googlebot arrives like a new visitor. If primary content appears only after a localStorage token, special consent cookie, or geolocation result exists, the crawler may receive an empty state.
Serve a useful default version. Personalization should enhance it, not replace the URL's entire subject.
7. Hydration fails
SSR may send complete HTML, then a hydration error deletes content or creates a different DOM. Search may still read the response, but user experience and post-render links can break.
Monitor console errors, hydration mismatch warnings, and failed requests in production. Failures affecting bots or slower devices are easy to miss in routine QA.
CSR, SSR, SSG, and hybrid rendering
| Rendering model | SEO advantage | Risk |
|---|---|---|
| CSR | Flexible frontend architecture | Rendering dependency and empty app shells |
| SSR | Content arrives in HTML | Server load and caching complexity |
| SSG | Fast, stable, crawler friendly | Requires rebuild strategy |
| Hybrid | Match rendering to each route | More conventions to maintain |
Blogs, landing pages, categories, and documentation usually benefit from SSR or SSG. An authenticated dashboard does not need indexing, so CSR is perfectly appropriate there.
Dynamic rendering has been used to send special HTML to bots, but maintaining two versions creates drift and cost. Whenever possible, serve the same pre-rendered core content to users and crawlers.
A step-by-step JavaScript SEO audit
Step 1: Compare three versions
Place these side by side:
- source HTML;
- browser-rendered DOM;
- URL Inspection rendered HTML or screenshot.
Anything present only in your browser but absent from URL Inspection is a strong lead.
Step 2: Review requests and resources
Find assets returning 403, 404, CORS errors, timeouts, or robots blocks. One failing API can remove an entire content region even when the main bundle loads.
Step 3: Audit metadata
Titles, descriptions, canonicals, robots directives, and structured data must be route-specific. SPAs often retain metadata from the previous route or derive canonicals from unnormalized URLs.
The Meta Tag Checker shows the title, canonical, Open Graph tags, and headings supplied for a URL.
Step 4: Inspect links and sitemaps
Internal links need href, sitemaps should contain only canonical URLs, and every listed URL must return the intended status. A sitemap cannot compensate for uncrawlable navigation.
Step 5: Measure performance
Large bundles and long tasks hurt users and make rendering more expensive. Run the Page Speed Checker, paying attention to LCP, INP, TBT, and unused JavaScript.
Step 6: Test templates, not just the homepage
Sample an article, category, product, filter result, pagination, and a missing URL. Most JavaScript SEO defects live in routes developers rarely open manually.
A typical failure
A recruitment site uses Vue to fetch job cards after the category component mounts. The category H1 exists in source, but every job card is generated by JavaScript. Each card uses @click on a <div> without an href.
Visitors can browse jobs normally. Google finds the category but has no crawlable route to job detail. The sitemap contains job URLs, yet discovery is slow and pages receive almost no internal links.
The fix is not to remove Vue. The team changes cards to <a href>, server-renders the initial list, keeps interactive filters on the client, and returns real 404s for expired jobs. The architecture remains modern while discovery stops depending on luck.
Pre-release checklist
- Primary content exists in HTML or renders reliably.
- Valid routes return
200; removed routes return404/410. - Important navigation uses
<a href>. - Canonical and robots directives exist in source and remain stable.
- Required CSS, JavaScript, and APIs are crawlable.
- New-visitor empty states do not replace core content.
- Metadata updates correctly on navigation.
- Structured data appears in rendered HTML.
- Mobile and desktop expose equivalent primary content.
- URL Inspection sees what a visitor sees.
Monitoring JavaScript SEO after release
A one-time inspection catches obvious defects, but JavaScript applications change frequently. Add a small set of production checks so SEO failures surface before Search Console reports a trend.
Monitor representative public routes with an HTML-level test:
- expected title and canonical exist in the response;
- the primary heading and a recognizable content fragment are present;
- status code matches the route state;
- at least one important internal link has a real
href; - robots directives do not change unexpectedly.
Run a second rendered-browser check for content that legitimately depends on hydration. Capture console errors, failed network requests, final canonical, structured data, and a screenshot. The HTML test protects crawler basics; the rendered test protects the actual application.
Choose URLs by template rather than traffic alone. A homepage monitor can stay green while product detail, pagination, or localized routes break. Keep one stable fixture for every indexable template and one negative fixture that must return 404.
Release annotations are equally useful. When indexed pages or impressions fall, knowing exactly when a router, consent manager, rendering framework, or API changed shortens diagnosis. Without that history, teams often blame an algorithm update for a regression introduced by their own deployment.
For larger sites, compare source HTML and rendered DOM automatically. Alert when the rendered page loses a large share of text or links, or when content appears only after a delayed user action. These checks are not substitutes for URL Inspection, but they catch preventable mistakes every day.
Full check: use the SEO Checker on a representative URL and a free SEO audit to detect repeated issues across templates.
Conclusion
JavaScript does not make SEO fail. Content that exists only after clicks, incorrect status codes, links without href, and late-changing metadata cause the real damage. Make the initial response meaningful, keep URLs and statuses honest, then use JavaScript to improve the experience rather than hide the core content.
Reference: Google Search Central – JavaScript SEO basics.
Frequently asked questions
Can Google execute JavaScript?
Must every Vue or React site move entirely to SSR?
Why should JavaScript not remove a noindex tag?
Nhận bản tóm tắt SEO checklist qua email
Đăng ký để nhận bản tóm tắt các bước tối ưu SEO quan trọng nhất từ bài viết này.
Nhập email để tải template audit SEO 1 trang, dùng ngay cho website của bạn.
Check your website for free
Run an SEO audit or check your traffic quality now — no signup required.