Guide

SEO basics for single-page apps (why your Lovable site might be invisible to Google)

Published · 6 min read

You built a site, published it, and waited. Weeks later it still doesn’t show up when you search for it, and the link preview in Slack is blank. Often the cause isn’t your content. It’s how the page is delivered: many AI-built sites are single-page apps (SPAs) that build every page in the visitor’s browser with JavaScript.

“Invisible” is a slight exaggeration. Google can run JavaScript, and some platforms now work around the problem for you. But plenty of other crawlers, preview bots and tools only read the HTML your server sends. This guide explains what’s going on, what Google actually says, and the short list of things worth fixing.

What an SPA sends before JavaScript runs

When a browser asks a typical React and Vite single-page app for a page, the server often replies with something like this:

<!doctype html>
<html>
  <head>
    <title>My App</title>
  </head>
  <body>
    <div id="root"></div>
    <script type="module" src="/assets/index.js"></script>
  </body>
</html>

Everything a person sees is added afterwards by that script. A visitor with a normal browser never notices. A crawler that doesn’t run JavaScript sees one generic title and an empty box, on every URL of your site.

Patch checked. The page was a single empty div and a lot of hope.

The jargon for this is client-side rendering. web.dev’s rendering guide defines it as rendering an app in the browser with JavaScript, and says it “can work, but often needs additional testing and overhead”.

What Google says about JavaScript

Google’s JavaScript SEO basics guide is the official word. The short version:

  • Google can render JavaScript. It processes pages in three phases: crawling, rendering and indexing. Rendering uses a headless version of Chromium.
  • Rendering can wait. Pages go into a render queue. Google says a page “may stay on this queue for a few seconds, but it can take longer than that.”
  • Not everyone renders. Google still calls server-side rendering or pre-rendering “a great idea”, partly because “not all bots can run JavaScript.”
  • Workarounds aren’t the goal. Google’s page on dynamic rendering (serving a pre-rendered copy only to bots) calls it “a workaround and not a recommended solution”, and suggests server-side rendering, static rendering or hydration instead.

So an SPA isn’t automatically invisible to Google. But it is relying on an extra step that can be delayed or can fail, and it gives nothing at all to crawlers that skip that step.

Where Lovable fits

Lovable’s own docs are clear about this, which helps. Older Lovable projects use React and Vite, where, as the TanStack Start upgrade guide puts it, “the visitor’s browser then builds the content with JavaScript.”

To cover the gap, Lovable serves pre-rendered copies of published pages to a verified list of crawlers. Its SEO and AEO page lists search engines such as Google and Bing, AI search crawlers, social preview bots and verified SEO tools. It also says: “Unverified bots and link checkers see the regular single-page app.”

Lovable says apps created from 13 May 2026 (22 June 2026 on Enterprise plans) use TanStack Start, which renders each page into finished HTML on the server. Older projects can upgrade from project settings or chat. The docs say upgrading is optional, uses credits, and that libraries which only work in a browser can break server rendering, so test every page afterwards.

If you built with another tool, check what it generates. If “View page source” shows an empty container, the rest of this guide applies to you.

What to fix

1. Send real HTML

This is the fix that solves most of the others. There are three common approaches, defined on web.dev:

  • Server-side rendering: the server builds the HTML for each request.
  • Static rendering: a separate HTML file for each URL, made at build time.
  • Pre-rendering: running the app at build time and saving its first state as HTML.

For a Vite app, the Vite SSR guide describes pre-rendering routes into static HTML, which it calls a form of static site generation. It also says its SSR API is low-level and points most people to higher-level plugins and frameworks. If your builder offers a server-rendered template, that’s usually the simplest route.

2. Give every page its own title and description

Google’s title link guidance asks for a descriptive, concise <title> on every page, and warns against repeated or boilerplate titles. Its snippet guidance says identical descriptions on every page “aren’t helpful”. SPAs often have exactly that: one title and description in the shell, shared by every route.

<title>Pricing | Acme Bookings</title>
<meta name="description" content="Plans for small salons, from one chair to five.">

3. Add Open Graph tags per page

Many link previews in social and chat apps are built from Open Graph tags. The Open Graph protocol lists four basic ones: og:title, og:type, og:image and og:url. Lovable’s SEO page makes the same point for its own apps: each page still needs its own Open Graph tags.

<meta property="og:title" content="Pricing | Acme Bookings">
<meta property="og:type" content="website">
<meta property="og:url" content="https://acmebookings.example/pricing">
<meta property="og:image" content="https://acmebookings.example/og/pricing.png">

4. Publish a sitemap.xml

A sitemap lists the URLs you want found. Google’s sitemap guide says to use full, absolute URLs and to include only the URLs you want in search results. You can submit it in Search Console, or add a Sitemap: line to robots.txt. Lovable notes it creates a robots.txt with new projects “but not always a sitemap”, so check.

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://acmebookings.example/pricing</loc>
  </url>
</urlset>

5. Keep robots.txt simple

robots.txt tells crawlers which URLs they may fetch. Google says it is “not a mechanism for keeping a web page out of Google”: use noindex for that. And don’t block your JavaScript or CSS files if Google needs them to understand the page. For an SPA, it does.

User-agent: *
Allow: /

Sitemap: https://acmebookings.example/sitemap.xml

6. Set a canonical URL

If the same page is reachable at several addresses, a canonical tag says which one is the real one. Google’s canonical guide says to put it in the <head>, to use absolute URLs, and to add a self-referencing one on the canonical page itself. The JavaScript SEO guide adds that HTML is the best place for it.

<link rel="canonical" href="https://acmebookings.example/pricing">

7. Return real 404s

An SPA often answers every URL with the same page and a “200 OK” status, then shows “Not found” with JavaScript. Google calls this a soft 404, and its JavaScript troubleshooting guide notes it is “especially difficult” to avoid in an SPA. Its two fixes: redirect to a URL where the server returns a real 404 status, or add <meta name="robots" content="noindex"> to the error view.

8. Avoid hash routing

Some SPAs use URLs like /#/pricing, where everything after the # is handled by JavaScript. Google says not to use URL fragments to load different content, notes that you can’t rely on them working with Googlebot, and recommends the History API so each page has a real path like /pricing.

How to test

  • View page source, not Inspect. “View page source” shows what the server sent. Inspect shows what JavaScript built afterwards. If the source has no text, crawlers that don’t render get nothing.
  • Google’s tools. The URL Inspection tool in Search Console can run a live test and show a screenshot of how Google rendered the page. Google’s troubleshooting guide also suggests the Rich Results Test for checking the rendered HTML.
  • ShipPatrol. Our blank-without-JavaScript check fetches your pages without running JavaScript, then renders them in a real browser and compares the two. The meta tags check and sitemap and robots check cover items 2 to 5.

For more on what AI builders leave for you to finish, see what Lovable and Bolt don’t set up for you and our Lovable page.

Check your site

Run a free scan to see what a crawler gets from your homepage. If it’s an empty div, at least you’ll know.

Free scan

See what Patch finds on your site.

Free, no signup. You get a score, every issue with its severity, and full detail on the top three.

No signup needed. Not legal advice; every check names its source.

More guides