JavaScript SEO: make sure the links survive rendering
Google renders JavaScript with an evergreen Chromium. The problem is rarely rendering itself. It is links that never become anchors, and pages that depend on state a crawler does not have.
ArchiLinks research team ·
What a crawler sees
Googlebot has used an evergreen Chromium since May 2019. That settled the question of whether it can run modern JavaScript.
The practical risks are older ones: rendering happens after crawling and can be delayed, content behind clicks or logins never appears, and a link built from an onclick handler on a div is not a link. Before you check backlinks on website pages that you recently moved to a React front end, confirm that those pages show their content in the raw response or in the rendered HTML.
SSR, SSG, CSR: what changes for links
| Approach | Content in first response | Internal links as anchors | Good for |
|---|---|---|---|
| SSR (Next.js, Nuxt) | Yes | Yes, if you use real anchors | Public pages with changing data |
| SSG or prerender | Yes | Yes | Docs, blogs, marketing pages |
| CSR single-page app | No, empty shell | Only after rendering | Dashboards behind a login |
| Hybrid (SSR home, CSR app) | Per route | Per route | Most products with a public side |
Test one: raw HTML versus rendered HTML
If the key links appear in the first response, the question is closed. If not, compare with a headless render.
# raw response: are the links there?
curl -s https://new-shop.com/guides/ | grep -o '<a [^>]*href="[^"]*"' | head -20
# rendered DOM with headless Chrome
chrome --headless --dump-dom https://new-shop.com/guides/ | grep -c '<a 'Where outside links come in
A rendering bug hides your content. It does not erase the links other sites already gave you.
After a move to Next.js, Vite or a headless CMS, run toppages for the host and test the 20 most linked URLs for status, canonical and visible content. Do it first. If a page with 40 linking domains returns an empty shell or a client-side 404, fix it before anything else, because that is where your authority lands. The internal vs external equity page shows how to compare that list with your internal links, and the migration checklist puts the test inside a launch plan.
Frameworks matter less than discipline. Express with a template engine, a WordPress theme and a Next.js app router can all serve crawlable links. Each can also fail if a team ships anchors that only exist after a click.
Link and rendering checklist
- Navigation and pagination use
<a href>, not click handlers on other elements. - Every route returns a real status code. Soft 404 screens must return 404.
- A
noindexor canonical injected by JavaScript matches the one in the server response. - Fallback content in the first response is the real page, not a spinner that Google may index.
- Auth code does not redirect crawlers on public routes.
- CSS and JS files needed for rendering are not blocked in robots.txt.
- Lazy loading uses IntersectionObserver or native loading attributes, not scroll events.
Reading the Search Console evidence
Search Console answers most rendering questions if you ask the right report. Use URL Inspection, then View crawled page.
Compare three things: the HTML Google fetched, the screenshot, and the page resources that failed to load. A page that looks complete in your browser but empty in the screenshot is usually blocked by a script error or a disallowed resource, and the fix lives in your build, not in your content.
Remember the delay. A change you ship today appears in the inspection tool only after Google recrawls the URL, which can take days.
When SSR is worth it
Public pages that must rank: yes. Dashboards: no.
If a route should draw organic traffic, serve the content in the first response. If it sits behind a login, skip the complexity. Choose per route and not per project, and document the decision so the next developer does not undo it.
- Use the Rich Results test and URL Inspection to compare the rendered output.
- Test with the Search Console live test after each framework upgrade.