Skip to content
back to journal

lovable

Your Lovable App Isn't Ranking on Google. Here's the 5-Cause Fix.

Your Lovable app isn't on Google? Five root causes, ranked. SPA rendering, missing per-route metadata, sitemap gaps, cache config, and how to fix each one.

Ralph Duin · 8 min read
XLI
Your Lovable App Isn't Ranking on Google. Here's the 5-Cause Fix.

Your Lovable app isn't showing up on Google. You shipped it, you can see it at your-domain.com, you can site:your-domain.com Google and find approximately nothing. The page isn't broken — it's invisible to crawlers. This is the most common Lovable production-readiness gap, and it's almost always one of five root causes. Here's how to diagnose, then fix it.

The summary up front: Lovable generates a Vite + React SPA. SPAs ship an empty <div id="root"> to crawlers and rely on JavaScript to build the page. Google can technically render JS, but the rendering is delayed, the queue is deep, and a brand-new low-authority site can wait weeks for the second pass. Bing and most AI crawlers don't render JS at all. If you want to rank, you have to make the HTML the crawler sees match the page a user sees — and that means one of a small number of well-defined fixes.

Quick triage — which of the five is it?

Open a terminal and run, against your live site:

curl -sL -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" https://your-domain.com/ | head -c 2000

What do you see in the first 2 KB of HTML?

  1. An empty <div id="root"> and a <script src="/assets/index-...js"> tag, no title or meta tags filled in → cause is #1 below (no SSR, no prerender).
  2. A <title> tag that says "Lovable App" or your old project name, the same on every URL → #2 (no per-route metadata).
  3. A proper <title> and meta but it's all the same across /, /pricing, /blog#3 (one-size-fits-all metadata).
  4. HTTP 200 on / but 404 / 403 on /sitemap.xml or /robots.txt#4 (no discovery surface).
  5. Cache headers are no-store, private, or CDN says cf-cache-status: BYPASS#5 (cache config blocking crawlers).

Then go fix that one.

Cause 1 — Lovable ships a Vite SPA with no SSR

This is the most common cause. The exported Lovable codebase is index.html + a Vite bundle. The HTML body is approximately empty until JavaScript runs. Googlebot can render JS, but:

  • The render queue runs days behind the crawl queue for low-authority sites.
  • Bing, DuckDuckGo, and most AI crawlers (Perplexity, ChatGPT, Claude crawler) do not render JS at all.
  • If the page touches window, document, or any browser-only API at module scope during render, the Googlebot render fails silently and the page is dropped.

The fix is one of four, in increasing order of effort and reward:

  1. Prerender the Lovable export with Prerender.io or Cloudflare Workers HTML capture. Cheapest, fastest. The proxy serves cached static HTML to bots, the real Vite app to humans. Solves the indexing problem without rewriting code. Trade-off: prerendered HTML drifts when the SPA updates; you need a purge story.
  2. Static export the Vite app at build time. Works if your routes are known at build time and don't need per-request data. Output is plain HTML that crawlers love.
  3. Migrate to Next.js. Single biggest leap in production-readiness. SSR + ISR + App Router give you per-route metadata, server components, native sitemap generation, and a CI surface. See the conversion playbook and the migration service.
  4. Migrate to Astro or Remix. Lower lift than Next.js, gives you SSR. Less mature tooling around handoff/MCP/team workflows.

For more on which of these to pick, see SEO for Lovable Apps.

Cause 2 — Per-route <title> and <meta> aren't being set

In a React SPA, the per-route title is usually set client-side via react-helmet, react-helmet-async, or a custom hook. Crawlers that don't run JS see whatever was in the initial HTML's <head> — typically the project default ("Lovable App", "Vite + React + TS"). Every URL has the same title.

The fix: whichever rendering path you pick (prerender / static export / Next.js migration), make sure the per-route metadata is in the server-rendered HTML, not just the client-side helmet. In Next.js this is automatic via the metadata export in each page.tsx. In a prerendered SPA, it's the prerender tool's job — verify the prerendered output actually has the per-route titles set.

Cause 3 — Metadata exists but it's all the same

Sometimes the per-route metadata wiring exists but every route is using the same global default. Symptom: view-source: on /, /about, /pricing all show identical <title> and <meta name="description">.

The fix: each route needs unique metadata. In a Lovable codebase that's typically:

// src/pages/Pricing.tsx
import { useEffect } from "react";
export default function Pricing() {
  useEffect(() => {
    document.title = "Pricing — YourBrand";
    // and update meta description, og:title, etc.
  }, []);
  // ...
}

If you're prerendering, that useEffect runs during prerender and the HTML output captures the updated title. If you're not prerendering, the useEffect runs in the user's browser after the crawler already left — so the crawler sees the default. Cause 3 collapses back into Cause 1 (need server-rendered HTML).

If you've migrated to Next.js, each route exports its own metadata object — done. See the Lovable.dev to Next.js migration prompts for the exact refactor.

Cause 4 — No sitemap.xml, no robots.txt, no discovery surface

Crawlers find your URLs primarily through links from other pages and through your sitemap.xml. New low-authority sites have almost no inbound links, so the sitemap is the discovery surface.

The fix:

  1. Generate a real sitemap.xml. In Next.js: app/sitemap.ts with the routes from your data layer. In a prerendered Vite SPA: a build-time script that lists all known routes. Submit it in Google Search Console (Sitemaps section) and Bing Webmaster Tools.
  2. Write a real robots.txt. Even a one-liner pointing at the sitemap helps:
    User-agent: *
    Allow: /
    Sitemap: https://your-domain.com/sitemap.xml
    
  3. Don't blanket Disallow: /. I've seen Lovable projects deploy with a placeholder robots.txt that blocks the entire site. Five-second check, ten-day index drop.
  4. Verify the sitemap actually returns 200 and contains URLs. curl -sL https://your-domain.com/sitemap.xml should return well-formed XML with <loc> entries. Empty or 404 = your discovery surface doesn't exist.

Cause 5 — Cache or proxy config is blocking the crawler view

Less common but ugly when it happens. Your Cloudflare config, your origin headers, or a custom Worker is serving different content to bots vs humans — sometimes accidentally.

Symptoms and fixes:

  • cache-control: no-store on HTML: prevents edge caching, slows crawl rate, and on poor cache layers can starve crawlers entirely. Fix: use s-maxage=3600, stale-while-revalidate=86400 for HTML; reserve no-store for genuinely private routes.
  • cf-cache-status: BYPASS everywhere: Cloudflare is bypassing cache; usually because your origin sends cache-control: private. Fix: make the origin send proper public cache headers, then cf-cache-status should become HIT over time.
  • A Cloudflare Worker that geo-blocks or UA-filters: rare but I've seen Workers written to "improve security" by blocking unknown User-Agents — which includes some legit crawlers. Fix: allowlist Googlebot, Bingbot, and the AI crawlers (PerplexityBot, ChatGPT-User, ClaudeBot, Google-Extended) explicitly.
  • HSTS preload misconfigured (very rare): if your HSTS header is wrong, some crawlers may stall on the security handshake. Fix: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload on every HTTPS response.

Order of operations (don't skip this)

The temptation when nothing ranks is to do everything at once. Don't. Each fix takes a different time to show up in Google. Do them in this order:

  1. First: verify the basics — robots.txt exists, sitemap.xml exists, both return 200, sitemap has real URLs. Effect: hours to days.
  2. Second: get server-rendered HTML — prerender, static export, or Next.js migration. Effect: days to weeks to be re-crawled.
  3. Third: per-route metadata in the server-rendered HTML. Effect: weeks for SERP titles + descriptions to update.
  4. Fourth: submit the sitemap in Google Search Console + Bing Webmaster Tools. Effect: accelerates re-crawl.
  5. Fifth: fix cache / proxy issues so the re-crawl is consistent. Effect: stabilises rather than accelerates.
  6. Sixth: build authority — internal links, external links, content depth. Effect: months. This is the real ranking work; the above are just unblocking it.

If you skip step 2, every other step is performative. The crawler still sees an empty HTML body.

When to migrate vs patch

Patching (prerender + sitemap + metadata fixes) is right when:

  • The product is settled and you're not actively shipping major features.
  • Your team is small and can't afford a 4-week migration window.
  • The Lovable codebase has minimal custom backend logic to migrate.

Migrating to Next.js is right when:

  • You're already feeling the other Lovable limits (no monorepo, no submodules, single-branch sync, no multi-env).
  • The product is growing and SEO is foundational, not bolted-on.
  • You want a real CI/CD surface, observability, and a codebase your team can hand off.

Most teams patch first, then migrate when the patch's edges start to fray. That's a reasonable path. See the Lovable to Next.js migration service when you're ready.

FAQ

How long until my Lovable app starts ranking after I fix this?

For a low-authority site that just fixed the rendering problem: 2–6 weeks for Google to recrawl, re-render, and update the index. New URLs without inbound links may take longer — submit them via GSC URL Inspection's "Request Indexing" button to accelerate.

Can Google see my Lovable app at all?

It can crawl the HTML, yes. Whether it sees your actual content depends on whether you ship server-rendered HTML (yes) or client-rendered JS (maybe, slowly, sometimes never). The curl -A "Googlebot/2.1" test above is the truth.

Does Lovable have an SSR option?

Not natively. The output is Vite + React Router. To get SSR you migrate to a framework that ships it: Next.js, Astro, or Remix. See Lovable alternatives for the comparison.

Will adding <meta> tags via react-helmet fix my rankings?

Only for the slice of crawlers that render JavaScript. Bing, most AI crawlers, and the "first pass" of Googlebot don't. If your content needs to rank on Bing or be cited by AI assistants, the metadata needs to be in the server-rendered HTML.

Is Prerender.io enough or do I need to migrate to Next.js?

Prerender is enough for the SEO problem. It's not enough for the broader production-readiness problem (monorepo, multi-env, CI gates, observability, the team-handoff story). Pick patching when SEO is the only blocker. Pick migration when SEO is one of several blockers.

Related from the Lovable cluster

— Inspired By Frustration

▢ end of post
XLinkedIn