You have a site built with React, Vue, or Angular? Your online store loads content via JavaScript, and search engines struggle to read the pages? You are not alone. We see this every day in projects that come to us: modern sites with JavaScript frameworks that Google does not index properly. The problem is not the framework — it's how rendering is served.
In this practical guide, we explain why it happens, which solutions exist (SSR, SSG, ISR, hybrid prerendering), and how to implement them without reinventing the wheel. No abstract theory: we start from code we have written and tested on real projects.
The Problem: JavaScript and crawlers don't speak the same language
Modern search engines (Google, Bing) can execute JavaScript, but with strict limits: limited crawl budget, timeouts (often 10 seconds), and inability to handle complex user interactions. A site that loads everything via JS (Client-Side Rendering or CSR) forces Google to:
- Download almost empty HTML
- Download large JS bundles (often hundreds of KB)
- Execute the code in a headless browser
- Wait for async data to arrive
If any of these steps fails, the page is indexed as an empty shell. Zero results in SERPs for important keywords.
At Meteora Web, we inherited projects with this issue: a React e-commerce that indexed only the homepage. After implementing SSR with Next.js, product pages went from 0 to 1500 daily impressions in 6 weeks.
Sponsored Protocol
Signs your site has a JS rendering problem
- No content in Google cache: search
site:yourdomain.comand check results. If you see only a few pages, the rest is not indexed. - Missing content in preview: use the “URL Inspection” tool in Google Search Console. If the preview is empty or shows only the empty skeleton, JS rendering failed.
- Slow mobile pages: CSR often gives high First Contentful Paint (FCP) because the browser must download and process JS before showing any content.
The solutions: SSR, SSG, ISR, hybrid prerendering
There is no magic wand. The choice depends on use case and tech stack.
Server-Side Rendering (SSR)
The server generates complete HTML for each request. The browser receives ready-made pages without waiting for JS. Ideal for dynamic content (e-commerce, dashboards, portals).
Example with Next.js 13+ (App Router):
// app/products/[slug]/page.jsx
export default async function ProductPage({ params }) {
const res = await fetch('https://api.example.com/products/' + params.slug);
const product = await res.json();
return (<div><h1>{product.name}</h1><p>{product.description}</p></div>);
}Note: SSR requires a running Node.js server. With Next.js, deployment on Vercel or on a VPS with PM2 is straightforward. We prefer VPS on Hetzner or AWS EC2 and manage the process with systemd.
Sponsored Protocol
Static Site Generation (SSG)
Content is generated at build time. Each page becomes a static HTML file. Ideal for blogs, landing pages, documentation. Fast, secure, zero server load.
Example with Next.js:
// app/blog/[slug]/page.jsx
export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json());
return posts.map(post => ({ slug: post.slug }));
}
export default async function BlogPost({ params }) {
const res = await fetch('https://api.example.com/posts/' + params.slug);
const post = await res.json();
return (<article><h1>{post.title}</h1><div>{post.content}</div></article>);
}Pro: maximum speed, static hosting (Netlify, Vercel, S3+CloudFront). Con: every content change requires a rebuild. For sites with infrequent updates, it's perfect.
Incremental Static Regeneration (ISR)
A hybrid: static pages that automatically regenerate at defined intervals (e.g., every 60 seconds). Combines the benefits of SSG and SSR.
// app/products/[slug]/page.jsx
export const revalidate = 60; // seconds
export default async function ProductPage({ params }) { ... }ISR is great for e-commerce with stable catalogs but prices that change hourly. We used it for a client with 10,000 products: initial build of 5 minutes, then incremental updates without downtime.
Sponsored Protocol
Hybrid prerendering (Nuxt, Gatsby, Astro)
Not just Next.js. There are valid alternatives for every framework:
- Nuxt 3 (Vue): supports SSR, SSG, and hybrid mode (per page).
- Gatsby (React): pure SSG with plugins for dynamic data.
- Astro (any UI): zero initial JS, only static HTML + interactive islands.
- SvelteKit: native SSR and SSG.
The right choice depends on your team, not just hype. When we use Laravel with Inertia.js, we handle SSR part with Laravel itself (using server-side rendering of Inertia combined with Vite).
How to implement SSR/SSG without going crazy: step-by-step guide
Suppose we need to migrate a React site (CSR) to Next.js. Here are the practical steps.
1. Audit the current project
- List all pages and their dynamic data (APIs, databases).
- Identify dependencies that might break in Node environment (e.g., localStorage, window).
- Use Google Search Console to see how many indexations you are losing.
2. Initial setup with Next.js
npx create-next-app@latest --typescript
cd new-app
npm run dev3. Convert a critical page to SSR
Take the homepage. Move API calls into the page component and use async. Ensure all client components are marked with 'use client' if needed.
Sponsored Protocol
// app/page.jsx (Server Component)
export default async function HomePage() {
const data = await getData();
return <div>...</div>;
}4. Test with Google and rendering tools
- Use
curlto see the returned HTML:curl http://localhost:3000 | grep '<title' - Paste the URL in Rich Results Test by Google (link). If the HTML includes the content, you are on the right track.
- Enable JavaScript Rendering Checker in Search Console (Settings > Crawling > Rendering).
5. Handle deployment
For SSR: deploy on VPS with Node.js + PM2 + Nginx as reverse proxy. For SSG: build and upload to static hosting.
We have automated builds with GitHub Actions (check our practical guide on Domain Driven Design for automation analogies).
Common mistakes (and how to avoid them)
Not testing rendering on Google
Many developers test only client-side rendering. Google is not a modern browser. Always test with URL Inspection Tool.
Forgetting error pages and redirects
If your 404 or 500 page is client-side handled, Google will see a blank page. Ensure errors are server-side rendered.
Ignoring data preloading
With SSR, if your API takes 3 seconds, the page will be slow for everyone (users and crawlers). Use Redis caching or optimized database queries. We recommend application-level caching (e.g., with Redis) for data that changes infrequently.
Sponsored Protocol
Essential tools to diagnose rendering
- Google Search Console (URL Inspection)
- Lighthouse (with “Emulate mobile” flag)
- WebPageTest (watch the rendering filmstrip)
- Puppeteer/Playwright for endpoint testing:
curlwith Google user agent
If you have never used Puppeteer, here is a quick command to see what Google sees:
# Replace URL with your site
curl -H "User-Agent: Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
-H "Accept: text/html,application/xhtml+xml" \
https://www.yoursite.com | grep '<title'Summary — what to do now
- Check immediately if your site suffers from client-side rendering: compare how many pages Google indexed vs your actual pages.
- Identify the appropriate solution: SSR for dynamic content, SSG for static, ISR for a middle ground.
- Start with a pilot page (e.g., most visited product). Convert it to SSR/SSG and monitor impact in Search Console.
- Automate deployment: use GitHub Actions to build and upload to server or static hosting.
- Don't forget security and image optimization (see our case study on reducing image weight by 60%).
If you need a technical audit of your JavaScript site, contact us. We assess the situation and propose a concrete solution, without unrealistic promises.