Skip to content
BlackFig

Replit SEO not working: why Google can't see your Replit app and how to fix it

AntPublished 4 min read

Checked against Replit's documentation on 10 November 2026.

Quick answer

Replit's SEO rating and SEO Agent fix the technical basics, such as titles, meta descriptions, sitemap.xml and robots.txt. They can't fix an app that is private or serves the same empty HTML for every URL. Make the app public, put it on a custom domain, and make each page that should rank return its own title, description and content.

On this page
  1. Symptom
  2. Why it happens
  3. The fix
  4. How to prevent it
  5. When to get help

Symptom

The app has been live for weeks and nobody finds it through search. Or Google shows it with the wrong title, or with the same title on every page. Shared links preview with no image. The Publishing tool tells the same story:

Sometimes there's no rating at all. That is a clue in itself: Replit only rates public web deployments.

Why it happens

The app isn't public

When you publish, Sharing offers Public, Password protected, Workspace only and Invite only. Apps in an organisation workspace default to a private option. Visitors to a private app are asked to sign in through Replit first, and a search crawler can't do that.

Every URL returns the same page

Agent builds full-stack web apps, and many have a React front end that draws each page in the browser. The server sends one index.html for every route, with one <title> and no content until JavaScript runs. Google can run JavaScript, but you are relying on it, and many link-preview bots only read the HTML the server sends. A good Lighthouse SEO score can miss this: every URL has a title, it's just the same one.

The domain is borrowed

A .replit.app address works, but Replit's own SEO guidance is to connect a custom domain. If you add one later, every link and every page Google already indexed points at the old address.

The small tags are missing

Replit publishes the list of fixes Agent applies most often, and it reads like a list of what Agent-built apps usually leave out: unique titles and meta descriptions, alt text on images, a lang attribute on the html element, a viewport tag, link text that says where the link goes, colour contrast, robots.txt, sitemap.xml, Open Graph and Twitter card tags. None of these is hard. Together they decide whether a search result or a shared link looks like a real product. SEO Agent also checks AI readiness, because AI crawlers read the same markup.

Nobody wrote the content

SEO Agent handles the technical layer. Replit is clear that it doesn't write content. A landing page with one heading and three feature cards gives a search engine little to rank.

The fix

  1. Make it public. In Publishing, check Sharing. To change it on a live app, Replit makes you unpublish, choose the new option, then publish again. If you want a closed beta, keep the marketing pages in a separate public project.

  2. Look at what crawlers get. Fetch two different pages without JavaScript:

curl -s https://your-app.replit.app/ | grep -o "<title>.*</title>"
curl -s https://your-app.replit.app/pricing | grep -o "<title>.*</title>"

If both titles match and the body has no real text, crawlers see an empty shell.

  1. Run SEO Agent. On a paid plan, open the Growth pane and select Run scan with Agent on the SEO Rating card. Issues come back grouped as AI Readiness, Crawlability & Discovery, Landing Page Rendering & Metadata and Performance Proxies, each with a severity. Use Fix with Agent per issue or Fix all with Agent, review each task, then Apply changes to main version and republish so the rating recalculates.

  2. Give each route its own head. If Agent's fixes still leave one shared index.html, have the Express server fill in the title and description per route before sending it:

// server/seo.ts
import { readFile } from "node:fs/promises";
import path from "node:path";
import type { Express } from "express";
 
const SITE = "https://www.example.com"; // your custom domain
const pages: Record<string, { title: string; description: string }> = {
  "/": { title: "Example Co: booking for small venues", description: "Take bookings and deposits online in minutes." },
  "/pricing": { title: "Pricing | Example Co", description: "Plans for venues of every size, billed monthly." },
};
 
const esc = (s: string) => s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
 
export function seoRoutes(app: Express, distDir: string) {
  app.get(Object.keys(pages), async (req, res, next) => {
    try {
      const meta = pages[req.path];
      const html = await readFile(path.join(distDir, "index.html"), "utf8");
      const head =
        `<title>${esc(meta.title)}</title>\n` +
        `<meta name="description" content="${esc(meta.description)}" />\n` +
        `<link rel="canonical" href="${SITE}${req.path}" />`;
      res.type("html").send(html.replace(/<title>.*?<\/title>/s, head));
    } catch (err) {
      next(err);
    }
  });
}

Register it before the static file handler and the catch-all route, and point distDir at your built client folder. This fixes the head, not the body. For pages that need to rank on their words, such as the homepage, pricing and guides, prerender them to real HTML. Replit recommends Static deployments for content-heavy sites, but Static doesn't work for Agent apps, so in practice that means a separate Static project for the marketing site.

  1. Add robots.txt and a sitemap. SEO Agent can add both. If you write them by hand, keep them in the server so they always match your domain:
// server/seo.ts, alongside seoRoutes (SITE as above)
app.get("/robots.txt", (_req, res) => {
  res.type("text/plain").send(`User-agent: *\nAllow: /\nSitemap: ${SITE}/sitemap.xml\n`);
});
  1. Connect the custom domain and republish. Open Publishing, then Domains. Republish afterwards so social previews pick up the new production URL. Then submit the sitemap in Google Search Console.

How to prevent it

  • Decide before building which pages need to rank, and write it into replit.md: "Marketing pages must return their own title, description and H1 in the HTML the server sends."
  • Check the SEO rating after each publish. It runs automatically, usually within a minute or two.
  • Keep app screens and marketing pages apart. The app can stay a single-page app behind sign-in.

When to get help

If the app needs a proper marketing site, or the routing has grown too tangled to add server-rendered pages safely, that's a bigger job. The guide to fixing vibe-coded apps shows where SEO sits among the other fixes, what makes a SaaS landing page convert covers the content side, and deploying a Replit app to production covers the release itself.

Run the free vibe-code health check for a quick read, or book a Rescue Sprint and I'll fix what search engines see.

Sources

The vibe-code rescue checklist, as a PDF

About 40 checks across auth, data, payments, errors, mobile and secrets, on two pages.

You get the PDF now and two short follow-ups over the next week. Reply “stop” and the rest never arrive.

Questions founders ask

Does Replit do SEO for me?

Partly. Every published public app gets a Lighthouse-based SEO rating, and on paid plans SEO Agent scans the app and applies fixes for metadata, crawlability and structured data. Replit's docs say SEO Agent does not write content or build topical authority for you.

Why is there no SEO rating on my published Replit app?

The rating only runs for public Autoscale, Reserved VM and Static deployments. Private apps and Scheduled deployments don't get one, and it can take a minute or two after a publish to appear.

Do I need a custom domain for SEO on Replit?

It isn't required, but Replit recommends one, and social link previews use your app's public production URL. Connect it before you start building links, and point canonical tags at it.

Ant

Product designer who builds MVPs, based in Nottingham. 10+ years designing digital products, and the only person at BlackFig. More about me