Here's How I Made Lovable SEO-Friendly with Static Site Generation (SSG)
React apps built with Lovable are fast and interactive - but search engines struggle with client-side rendering. Here's how I implemented Static Site Generation to get the best of both worlds.
Melbourne-based performance marketing consultant helping B2B and e-commerce brands grow through Google Ads, SEO, and analytics.
Executive Summary
Lovable generates React Single Page Applications (SPAs) that rely on client-side rendering. While great for interactivity, this means search engines initially see an empty page until JavaScript executes.
By implementing Static Site Generation (SSG), I pre-render each page to HTML at build time. Search engines now see fully-formed content immediately, while users still get the rich React experience once JavaScript loads.
The Problem: Empty Pages in Search Console
When I checked Google Search Console, it showed my homepage as essentially empty. The "View Crawled Page" feature revealed just a loading shell - no content, no headings, no text for Google to index.
This is the classic SPA problem. The HTML file contains only <div id="root"></div> and a script tag. All the actual content lives in JavaScript bundles that must download and execute before anything appears. While Google can render JavaScript, it's a slower two-phase process that can hurt rankings.
The Solution: Static Site Generation
SSG pre-renders each route to a complete HTML file during the build process. When a crawler (or user) requests a page, they get real HTML content immediately - no JavaScript required for the initial view.
SSG vs SSR: What's the Difference?
Both approaches solve the same problem - getting HTML to the browser before JavaScript runs - but they work differently:
Static Site Generation (SSG)
- • HTML generated at build time
- • Same HTML served to every visitor
- • Fastest possible response times
- • Perfect for content that doesn't change per-user
- • Requires rebuild to update content
Server-Side Rendering (SSR)
- • HTML generated on each request
- • Can personalise content per visitor
- • Slightly slower (server processing time)
- • Better for dynamic, user-specific content
- • Content always fresh without rebuilds
Why I chose SSG: My site is primarily static marketing content - service pages, articles, and a contact form. There's no per-user personalisation needed, so SSG gives me the fastest possible load times with zero server costs. The pages are pre-built and served directly from Netlify's CDN.
Here's what I implemented to make this work with Lovable and Netlify:
1. Server Entry Point
Created entry-server.tsx using React's renderToString andStaticRouter to render components to HTML strings on the server.
2. Node.js Build Script
Built a custom build-ssg.mjs script that builds the client, builds the server entry, then renders every route to static HTML files.
3. Dynamic Metadata with react-helmet-async
Each page defines its own title, description, and Open Graph tags via Helmet. The SSG process extracts these and injects them into the HTML head - crucial for SEO and social sharing.
4. No-JavaScript Fallback
Implemented a no-js /js class toggle pattern so content remains visible even if JavaScript fails to load. Pre-applied visibility classes during SSG to ensure crawlers always see content.
5. URL Normalisation
Configured Netlify redirects to enforce non-trailing-slash URLs and prevent duplicate content issues. All canonical tags point to the normalised version.
6. Client-Side Hydration
Updated the client entry to use hydrateRoot in production instead of createRoot. This attaches React to the existing HTML rather than replacing it.
Key Technical Challenges
Browser API Polyfills
React components often use localStorage,window, ornavigator. Since SSG runs in Node.js, I had to polyfill these APIs in the build script to prevent crashes.
Single HelmetProvider
A tricky bug: having multiple HelmetProvider wrappers breaks SSR metadata extraction. The solution was ensuring only the server entry's provider exists during rendering, with HelmetProvider.canUseDOM = false explicitly set.
Animation Visibility
Scroll animations that start invisible (opacity: 0) caused content to be hidden in the static HTML. The fix was pre-applying theis-visible class during SSG and using CSS selectors to handle the no-JS case.
The Results
- Full content in View Source - All page content, metadata, and structured data visible without JavaScript
- Faster Time to First Contentful Paint - Content renders immediately without waiting for JS bundles
- Proper Search Console indexing - Google now sees complete pages instead of empty shells
- Working no-JS fallback - Content remains accessible even if JavaScript fails
Try It Yourself
Want to implement SSG on your own Lovable project? Copy this prompt and paste it into Lovable:
I want to implement Static Site Generation (SSG) for my Lovable-built React app so that search engines can properly index my content. Please help me set up the following: 1. Create a server entry point (src/entry-server.tsx) that uses React's renderToString and StaticRouter from react-router-dom/server to render pages to HTML strings. 2. Create a Node.js build script (scripts/build-ssg.mjs) that: - Builds the client bundle with Vite - Builds the server entry with Vite SSR mode - Polyfills browser APIs (localStorage, window) for Node.js - Renders each route to static HTML files - Injects the rendered HTML and head tags into the template 3. Configure react-helmet-async for dynamic per-page metadata: - Ensure only ONE HelmetProvider wraps the app - Set HelmetProvider.canUseDOM = false in the server entry - Extract and inject head tags during SSG 4. Update src/main.tsx to use hydrateRoot instead of createRoot in production for proper hydration. 5. Add a no-JS fallback so content remains visible if JavaScript fails: - Use a no-js/js class toggle pattern on the html element - Ensure scroll animations don't hide content in static HTML 6. Configure Netlify (netlify.toml) to: - Run the SSG build script - Redirect trailing slashes to non-trailing (301) - Serve .html files for clean URLs Here are my current routes that need to be pre-rendered: [List your routes here, e.g. /, /about, /services/example] Please implement this step by step, ensuring each piece works before moving to the next.
Note: Replace the placeholder routes with your actual page routes. This is a complex implementation that may take several iterations to get right - be patient and work through any errors step by step.
Should You Implement SSG?
Yes, if your Lovable app is a marketing site, blog, e-commerce store, or anything where organic search traffic matters. The implementation requires understanding React's server-side capabilities, but the SEO benefits are substantial.
How to Test Your SSG Implementation
Once you've deployed your SSG build, use these tools to verify everything is working correctly:
View Page Source (Ctrl/Cmd + U)
The simplest test. Right-click → "View Page Source" and check if your actual content, headings, and meta tags are visible in the raw HTML. If you only see <div id="root"></div>, SSG isn't working.
Pre-Rendering Checker
This tool fetches your URL without executing JavaScript and shows you exactly what search engines see. Compare the "Original" view (no JS) vs "Rendered" view (with JS) - they should show the same content.
technicalseo.com/tools/pre-renderingGoogle Search Console URL Inspection
The ultimate test. Enter your URL in the inspection tool, then click "View Crawled Page" → "HTML" to see exactly what Googlebot captured. After deploying SSG, request re-indexing and check again in a few days.
search.google.com/search-consoleRich Results Test
While primarily for testing structured data, this tool also shows you what Google sees when rendering your page. Check both the "HTML" and "Screenshot" tabs to verify content visibility.
search.google.com/test/rich-resultsCommand Line: curl or wget
For developers: run curl https://yoursite.com in terminal. This fetches raw HTML without any JavaScript processing - exactly how most bots see your page.
Pro tip: Test multiple pages, not just your homepage. Route-specific issues are common in SSG implementations - a missed route in your build script means that page reverts to client-side only.
Need help with technical SEO?
I help businesses implement proper tracking, analytics, and technical SEO foundations. If you're struggling with similar challenges, let's chat.
Get in TouchRelated Articles
GA4 Server-Side Tagging: Why It Matters Now
Shift your tracking from browser to cloud for better data quality and privacy compliance.
Digital Analytics & Attribution Guide 2026
A comprehensive guide to modern analytics and attribution in a privacy-first world.