A site built in an afternoon with Lovable, v0, Bolt or Replit usually works. The pages load, the layout holds up, the forms submit. Then it fails to appear in search, and the cause is hard to locate because nothing on screen looks broken.
The same defects turn up across all four platforms, because they optimise for the same thing: a preview that looks correct in a browser. Everything a crawler needs that a browser does not falls outside that goal. The list below is what to check, not a guarantee your build has all of it.
The defect list
The content is not in the HTML
Generated apps commonly render client-side. The server returns an empty root element and JavaScript fills it in. Google renders JavaScript eventually, but most AI agents and many crawlers read the raw response and find nothing there.
One command tells you which case you are in:
curl -s https://your-site.example | grep -c "some sentence from your homepage"A zero means the content does not exist until JavaScript runs. ax/content-without-js measures the same thing across the site, comparing the raw HTML against a separately rendered DOM and flagging main content that only appears after JavaScript runs. Fix this before anything further down the list, because the rest of the list applies to a page a crawler can already read.
Every route shares one title
The generator writes a title into the app shell and often gives the router no way to change it. Every page then returns the same one, so search results cannot distinguish a pricing page from a homepage.
Three rules cover this. core/meta-title checks presence and length, core/title-unique checks uniqueness across the site, and content/duplicate-title reports which pages collide. Meta descriptions repeat the pattern, and core/meta-description and content/duplicate-description cover them.
No sitemap, no robots.txt
Neither file is needed for a preview to work, so neither is usually generated. crawl/sitemap-exists checks for an XML sitemap and whether robots.txt references it. crawl/robots-txt checks robots.txt exists, parses as valid syntax, carries no bare Disallow: /, and references your sitemap.
A client-rendered app depends on the sitemap more than a server-rendered one does, because there are no crawlable links to most of its routes.
No canonical tags
Client-side routers serve the same content at several URLs: with and without a trailing slash, and with tracking parameters attached. core/canonical checks that each page declares which URL is the real one.
No structured data
Nothing in the generation step produces JSON-LD, so most builds carry none. schema/organization checks for the block naming who publishes the site. schema/json-ld-valid validates whatever JSON-LD is present, which matters because an invalid block counts for nothing. On a site with articles, schema/article covers the attribution fields.
Placeholder copy still on the page
Typical finds include lorem ipsum, a heading that still reads "Your Company Here", a stray TODO, and a visible undefined where a value was missing. content/placeholder-text catches template leftovers and filler that shipped. content/stale-copyright catches a hardcoded footer year, which is smaller but reads as abandonment to a visitor.
Development URLs in production
The usual causes are an image pointing at localhost:3000, a link to a preview deployment, or a base URL hardcoded on the machine where it was written. content/dev-leakage finds localhost, private, staging and preview hosts on a production page.
Secrets in the bundle
Check this one first, for reasons unrelated to search. Generated apps put configuration in client-side code, and configuration sometimes includes a key that was never meant to leave the server. security/leaked-secrets scans HTML and JavaScript for exposed API keys and credentials. perf/source-maps flags source map references in production bundles, inline maps included. It reports the reference without confirming the .map file is fetchable, so a hit is a lead to check rather than a confirmed leak.
Heavy JavaScript
A generated single-page app ships a large bundle for a page that is mostly text. perf/js-file-size and perf/total-byte-weight measure the payload, and perf/render-blocking identifies what delays first paint. ax/token-weight measures the same problem from the other side, reporting how much of the page HTML is visible text rather than markup. That ratio is what an AI agent pays to read.
Accessibility basics
Generated markup is usually reasonable and misses the same handful of things. images/alt-text checks every image carries an alt attribute. a11y/color-contrast catches the low-contrast grey the design defaulted to. a11y/form-labels catches inputs with a placeholder and no label. core/h1 checks each page has exactly one, which generated hero sections often get wrong.
Broken internal links
Routes get renamed during a build session and the links to them do not. links/broken-links finds the ones returning 404 or 5xx.
AI crawlers and agent files
ax/ai-crawlers classifies which AI crawlers robots.txt allows and blocks, separating training crawlers from AI-search indexers and from the user-action fetchers that serve a live request someone made inside an assistant. ax/llms-txt checks for an llms.txt at the domain root. AI crawlers and robots.txt and the llms.txt guide cover both in depth.
Finding all of it in one pass
Every rule above runs in one audit. Install the CLI and point it at the deployed site:
curl -fsSL https://install.squirrelscan.com | bash
squirrel audit https://your-site.exampleLocal audits are free. Two settings matter for a generated app. Raise the page budget, because a duplicate title only surfaces once more than one page has been crawled: --coverage full takes it to 500 pages and --max-pages goes higher. Then sign in if you want ax/content-without-js, which is cloud-backed. Leave --render off for that rule, because forcing the crawl to render makes raw and rendered the same document and the comparison skips.
To get the findings in a form a coding agent can act on:
squirrel audit https://your-site.example --format llm --coverage fullThat output names the rule, the failing check and the affected URLs, which is what an agent needs to work back to the component behind each one.
Handing it to the agent that built the site
This works well on a generated site for two specific reasons. The agent already holds the whole codebase in context, and the codebase is small. A finding like a duplicate title on 14 pages maps to one component. A missing sitemap maps to one file generated at build time. There is rarely a legacy reason something is the way it is, which is what usually slows this work down on an older codebase.
The loop of audit, read, fix and re-audit is covered in fixing SEO issues with an AI agent, including how to stop the agent reporting a fix it never verified. Setup for the agent side is in the MCP server guide, with per-tool pages for Claude Code, Cursor and Codex.
Once the first pass is clean, wire the check into whatever deploys the site so the next session of vibe coding cannot undo it silently:
squirrel audit https://your-site.example --fail-on 'score<90'That exits non-zero when the score drops below the threshold. Generated code changes fast, and a regression introduced by a prompt is as invisible as the original defects were.
The order to fix them in
- Secrets and source maps, which are not an SEO problem and still belong first.
- Server-rendering the content, since nothing else applies until the HTML contains the page.
- Per-route titles and descriptions, usually one component change.
- Sitemap, robots.txt and canonical tags, mostly files generated at build time.
- Placeholder copy and development URLs, which are cheap to fix and visible to human visitors.
- Structured data, then the accessibility checks, then bundle size.
- AI crawler access and
llms.txt, once the content is reachable.
On a small generated site this is often one session's work, because the agent that wrote the code is still the fastest thing at editing it.
For a broader view of what an audit covers, the website audit tool runs against a URL without installing anything, and auditing website security with an agent goes deeper on the secrets and headers side.