Your Lovable app is fast and pretty. Google still can't find it.
I've shipped over a dozen MVPs with Lovable over the past year at Inithouse. The builder handles UI, routing, and deployment beautifully — but SEO is not part of the default stack. Every single app I launched needed manual fixes before Google would index it properly.
Here's the checklist I now run on every project before going live.
The Problem: SPAs Are Invisible by Default
Lovable apps are React single-page applications. That means the HTML Google receives on first request is mostly empty — a root div and some script tags. Without server-side rendering, crawlers see nothing.
This isn't unique to Lovable. Every SPA framework has this issue. But Lovable's target audience — solo builders shipping fast — often skips the SEO layer entirely. I did too, until I noticed zero organic traffic on projects that should have been ranking.
Fix 1: Generate a Real Sitemap
Lovable apps don't ship with a sitemap. If you have dynamic content (blog posts, listings, user profiles), you need one that updates automatically.
The approach I use: a Supabase Edge Function that queries the database and returns XML.
// supabase/functions/sitemap/index.ts
import { createClient } from "@supabase/supabase-js";
Deno.serve(async () => {
const supabase = createClient(
Deno.env.get("SUPABASE_URL")!,
Deno.env.get("SUPABASE_ANON_KEY")!
);
const { data: posts } = await supabase
.from("blog_posts")
.select("slug, updated_at")
.eq("published", true);
const urls = (posts || []).map(
(p) => `<url>
<loc>https://yourdomain.com/blog/${p.slug}</loc>
<lastmod>${new Date(p.updated_at).toISOString()}</lastmod>
</url>`
).join("");
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url><loc>https://yourdomain.com/</loc></url>
${urls}
</urlset>`;
return new Response(xml, {
headers: { "Content-Type": "application/xml" },
});
});
Then submit the function URL to Google Search Console under Sitemaps. I do this for every project — including Ziva Fotka, which runs the same codebase across five country domains.
Key detail: After deploying new content, manually resubmit the sitemap in GSC. Google can go weeks without re-fetching it on its own.
Fix 2: Dynamic Meta Tags
React Helmet or a custom useSEO hook — pick one, but you need dynamic <title> and <meta name="description"> tags per page. The default Lovable setup gives you a single static title across the entire app.
// hooks/useSEO.ts
import { useEffect } from "react";
interface SEOProps {
title: string;
description: string;
canonical?: string;
ogImage?: string;
}
export function useSEO({ title, description, canonical, ogImage }: SEOProps) {
useEffect(() => {
document.title = title;
const setMeta = (name: string, content: string) => {
let el = document.querySelector(`meta[name="${name}"]`)
|| document.querySelector(`meta[property="${name}"]`);
if (!el) {
el = document.createElement("meta");
el.setAttribute(name.startsWith("og:") ? "property" : "name", name);
document.head.appendChild(el);
}
el.setAttribute("content", content);
};
setMeta("description", description);
setMeta("og:title", title);
setMeta("og:description", description);
if (ogImage) setMeta("og:image", ogImage);
if (canonical) {
let link = document.querySelector('link[rel="canonical"]');
if (!link) {
link = document.createElement("link");
link.rel = "canonical";
document.head.appendChild(link);
}
link.href = canonical;
}
}, [title, description, canonical, ogImage]);
}
Call it at the top of every page component:
useSEO({
title: "How to Convert Live Photos to GIF",
description: "Turn your iPhone Live Photos into shareable GIFs in seconds.",
canonical: "https://yourdomain.com/blog/live-photo-to-gif",
});
This is client-side only, so it won't help with crawlers that don't execute JavaScript. But Googlebot does execute JS in most cases, and it's infinitely better than having the same generic title on every page.
Fix 3: Canonical URLs for Multi-Domain
If you run the same app on multiple domains (like I do with Ziva Fotka across .cz, .sk, .pl, .de, and .online), you need canonical tags pointing to the primary version. Without them, Google sees duplicate content and picks one arbitrarily — usually not the one you want.
Set the canonical based on the current domain:
const domain = window.location.hostname;
const canonicalBase = domain.endsWith(".sk")
? "https://yourdomain.sk"
: domain.endsWith(".pl")
? "https://yourdomain.pl"
: "https://yourdomain.com"; // default primary
useSEO({
title: pageTitle,
description: pageDesc,
canonical: `${canonicalBase}${window.location.pathname}`,
});
Each domain should have its own GSC property. Submit sitemaps separately per domain.
Fix 4: JSON-LD Structured Data
Google uses structured data to generate rich snippets. For a SaaS landing page, SoftwareApplication schema works. For blog posts, use Article. For tools like Be Recommended (an AI visibility checker I built), WebApplication fits.
export function JsonLd({ data }: { data: Record<string, unknown> }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
/>
);
}
// Usage on a blog post page
<JsonLd data={{
"@context": "https://schema.org",
"@type": "Article",
"headline": post.title,
"author": { "@type": "Person", "name": "Jakub" },
"datePublished": post.created_at,
"dateModified": post.updated_at,
}} />
Fix 5: Pre-Render Critical Pages
For pages that absolutely must be indexed (landing page, pricing, key blog posts), consider pre-rendering. You can use a service like Prerender.io or build a simple Cloudflare Worker that serves a cached HTML snapshot to crawlers.
I haven't needed this for most Lovable apps — Googlebot handles client-side rendering reasonably well in 2026. But if you're seeing "Discovered — currently not indexed" in GSC for important pages, pre-rendering is the nuclear option.
The Pre-Launch SEO Checklist
Before every Lovable app goes live, I run through this:
- Sitemap — Edge Function generating XML from DB, submitted to GSC
- Meta tags — Dynamic title + description per page via useSEO hook
- Canonical URLs — Set on every page, especially for multi-domain setups
- JSON-LD — At minimum on the homepage and blog posts
- robots.txt — Confirm it's not blocking anything important (Lovable default is fine)
- Open Graph — og:title, og:description, og:image for social sharing
- GSC verification — DNS TXT record, property confirmed, sitemap submitted
- Manual index request — For the homepage and top 5 pages, use Request Indexing in GSC immediately after launch
This takes maybe 30 minutes per project. The difference between doing it and not doing it is the difference between organic traffic and zero organic traffic.
Wrapping Up
Lovable is great for shipping fast. SEO is the part you bolt on after. None of these fixes are complex — they're just not included out of the box, and if you don't know to look for them, your app stays invisible.
I've been building and measuring MVPs at Inithouse using this exact playbook. If you're shipping Lovable apps and wondering why Google isn't picking them up, start with the sitemap and meta tags. Those two alone will get you most of the way there.
Questions or your own Lovable SEO tricks? Drop them in the comments.
Top comments (1)
“Your app is fast and pretty. Google still can’t find it.” — the most accurate description of SPAs ever 😄
This is a great checklist. I’d add that a lot of devs overestimate how quickly Google re-renders JS—“it works in DevTools” ≠ “it’s indexed.” Your sitemap + manual indexing combo is doing the real heavy lifting here.