Your Vibe Coded Site Looks Great and AI Cannot See a Word of It.
// table_of_contents▸
- 1.What a vibe coded site actually sends to a crawler
- 2.The split visibility problem
- 3.Why Bing decides whether ChatGPT can find you
- 4.How each builder handles rendering today
- 5.How to confirm whether your site has the problem
- 6.Fix the rendering first
- 7.The technical SEO layer
- 8.Getting cited in ChatGPT, Claude, and Perplexity
- 9.A pre-launch checklist
- 10.A prompt to paste into your builder
- 11.Where this is heading

Vibe coding ships a working site before lunch. Lovable, Bolt, v0, Replit, and Cursor turn a prompt into a deployed app in minutes, and the output usually looks polished enough to launch. The trouble shows up weeks later, when the traffic you planned for never arrives and the site never gets named in an AI answer.
The cause is almost always the same. Most of these tools default to a client-side rendered React app, so the HTML that reaches a crawler is nearly empty, and the real content only appears after JavaScript runs in the browser. We see it most weeks in client audits, where a site looks finished on screen but hands a raw fetch almost nothing. Google can mostly cope with that, but the AI engines that now answer a growing share of search queries cannot, and that is where vibe coded sites lose ground.
What a vibe coded site actually sends to a crawler
Open the page source of a typical vibe coded site and there is almost nothing there. A React app built by these tools usually returns one empty container and a script tag on the first request, something close to <div id="root"></div> followed by <script src="/assets/index.js"></script>. Everything a reader cares about gets added later.
That script writes in every heading, paragraph, product description, and FAQ answer after the page loads. A person with Chrome open sees the finished design and never notices the order it happened in. A crawler that does not run JavaScript sees the empty container, finds nothing to read, and moves on. So the page can look finished to you and still be blank to the machines you most need to reach.
The split visibility problem
Not every crawler reads a page the same way, and that gap is the whole reason vibe coded sites underperform. Some bots render JavaScript, some render it slowly, and the ones behind AI answers do not render it at all. The same page can win in one channel and be invisible in another.
| Crawler | Runs JavaScript | What it sees on a client-rendered site |
|---|---|---|
| Googlebot | Yes, on a delayed second pass | Full content, eventually |
| Google-Extended (Gemini) | Yes | Full content |
| GPTBot / OAI-SearchBot (ChatGPT) | No | Empty shell |
| ClaudeBot (Claude) | No | Empty shell |
| PerplexityBot (Perplexity) | No | Empty shell |
| Bing, Yandex, Baidu | Limited and unreliable | Partial or empty |
Google renders JavaScript through a headless Chrome engine. It crawls the raw HTML first, then queues the page for a second pass that runs the scripts and indexes the result. Onely's experiment found that this second wave makes JavaScript-heavy pages take roughly nine times longer to index than static HTML. The page can still rank, it just gets there slower and with far less margin for error.
The AI crawlers skip rendering entirely. When Vercel and MERJ analyzed more than 500 million GPTBot fetches, they found no JavaScript execution at all, and the same held for ClaudeBot, PerplexityBot, and the rest. These bots request the page, read the raw HTML, pull out the text, and leave. There is no second render to fall back on, so anything missing from that first response does not exist for them.
One exception is the reason this gets confusing. Google-Extended, the crawler behind Gemini and Google's AI Overviews, uses Googlebot's rendering pipeline, so it reads client-rendered content fine. That creates a strange split, where a vibe coded site can rank on page one of Google and appear in Gemini while showing up blank in ChatGPT, Claude, and Perplexity. Those three drive most AI assistant usage, so the blank-page result is the one that costs real money.
Why Bing decides whether ChatGPT can find you
It is easy to write Bing off as a rounding error next to Google. For a vibe coded site that is a costly assumption, because Bing's index is what grounds ChatGPT search. OpenAI confirmed at launch that ChatGPT search runs on Bing's index, and Seer Interactive's analysis of more than 500 ChatGPT citations found 87% matched Bing's top organic results for the same query. So your Bing ranking does a lot of the work in deciding whether ChatGPT ever surfaces your page.
Client-side rendering does double damage here. Bingbot has only limited and unreliable JavaScript rendering, weaker than Googlebot's, so a vibe coded SPA can fail to make it into Bing's index at all. The direct fetch from OAI-SearchBot then reads the same empty shell. The site drops out of ChatGPT from both directions, the Bing index it leans on and the live crawl it falls back to, even while it still ranks fine on Google. When we audit a client's vibe coded site, Bing Webmaster Tools is one of the first places we look, because it shows what Bing actually stored instead of what the browser paints for a human.
How each builder handles rendering today
The builders are not all in the same place on this, and the tool you picked largely decides how much work is ahead of you. A few now render on the server by default, one or two still ship pure client-side SPAs, and the rest sit in between with fixes you have to ask for. Knowing where your tool sits tells you whether you are starting from a good baseline or a rewrite.
v0 is the strongest starting point. Vercel's builder generates on the Next.js App Router with Server Components by default, so deployed pages are server-rendered and crawlers get the real content on the first fetch. It also wires up metadata and structured data through standard Next.js conventions, ships responsive layouts, and uses proper semantic tags. Much of the technical SEO layer is handled before you touch anything, so if AI citations are the goal, v0 saves you the hardest fix.
Lovable has moved fast. As of April 2026, all new Lovable projects build on TanStack Start, a full-stack React framework that runs on the server and streams complete HTML on the first request. Its May 2026 SEO and AI search release added automatic pre-rendering for older projects, on-demand SEO reviews in the builder, Semrush data in the chat, and an llms.txt manifest. Two caveats matter. Projects created before the April cutover stay client-rendered unless you migrate them, and any page that pulls content from a CMS, database, or API at runtime stays client-rendered and invisible to non-rendering bots, even on the new stack.
Replit sits in the middle. The Agent usually reaches for React or Next.js on anything with dynamic content, and its default React apps are client-side rendered, which is the problem pattern. Replit has narrowed the gap by upgrading its defaults, so new apps ship semantic landmark elements, meta tags, Open Graph previews, and a generated robots.txt and sitemap.xml. It also launched an SEO Agent that scans an app for discoverability issues and fixes a chunk of them. The rendering decision is still yours, so for a content site, tell the Agent to turn on server-side rendering or static generation rather than assume it did.
Bolt is the one to watch most closely. Bolt.new generates fast, but it ships client-rendered React, Vue, or Angular SPAs with the near-empty HTML shell from earlier, and there is no server-rendering default to lean on. A Bolt site can look finished and still read as blank to every AI crawler, and as a slow second-pass job to Google. If you build in Bolt and need the result found, plan from the start to move the public pages onto a server-rendered framework or put a pre-rendering layer in front of them.
Cursor is a different kind of tool, an AI code editor rather than a one-click builder, so it has no default stack or rendering mode. What it produces depends entirely on what you ask for. That is a strength here, because you can name a server-rendered framework like Next.js or Astro in the first prompt and get exactly that. You can also commit Cursor rules files that hold your SEO standards as instructions the model follows on every change, and the Cursor 2.0 browser tool lets the agent load a page and check how it renders. The architecture is fully on you, which is fine as long as you make the rendering call up front instead of after launch.
How to confirm whether your site has the problem
Three checks tell you where a site stands, and none need a paid tool. Each one catches a slightly different failure, so passing one is not proof the others pass.
Start with the raw HTML. Right-click a page, choose View Page Source, and you are looking at what a crawler receives before any script runs. Headings and body text mean the page is server-rendered, while an empty container with script tags means it is client-rendered. Next, disable JavaScript in your browser and reload the same page, which is roughly what a non-rendering bot sees, so a blank or skeleton page is your warning sign.
The third check is URL Inspection in Google Search Console, which shows the rendered HTML Google actually indexed and tells you whether the two-wave process picked up your content or stalled. Run all three on your most important pages, not just the homepage, since templates often render differently from one route to the next, and a clean homepage does not vouch for the rest of the site.
Fix the rendering first
Every other optimization depends on this one. If the content is not in the initial HTML, then schema, meta tags, and internal links have nothing to attach to. Three approaches solve it, in rough order of how completely they fix the root cause.
Server-side rendering is the most thorough. The server builds the full HTML for each request before sending it to the browser, using a framework made for it like Next.js, Nuxt, SvelteKit, or TanStack Start, so the content arrives complete on the first response. That is exactly what both Google and the AI crawlers need. Static site generation does much the same job at deploy time, pre-building pages into static HTML with tools like Astro or the static export modes of those frameworks, which for a marketing site, blog, or docs that do not change per request is usually the cleanest fit and the fastest to serve. Pre-rendering is the fallback, a middleware layer that spots crawler user agents and serves them a fully rendered snapshot while people still get the SPA, and it closes most of the visibility gap when rewriting the app is not realistic.
Which one fits depends on the site. A content site that needs to rank and be cited is better served by SSG or SSR, since pre-rendering patches over an architecture instead of fixing it. An app where most pages sit behind a login, with only a few marketing pages to be found, can pre-render those few and leave the rest alone.
Client-side rendering is not wrong everywhere, and we tell clients as much. A logged-in dashboard or internal tool with no public discovery need gains nothing from server rendering and only adds complexity. The rule we use is simple. Anything that has to be found by search or cited by an AI engine renders on the server, and anything behind a login can stay as it is. The expensive mistake is treating this as a post-launch cleanup, because asking for server rendering on day one costs a sentence in a prompt, while migrating a live client-rendered app costs a rebuild.
The technical SEO layer
Once content is in the HTML, the usual technical SEO work applies, and vibe coded output tends to miss the same things every time. Walking each route to confirm these are present is faster than learning it later from a flat traffic graph.
Start with the basics that SPAs routinely break. Each route needs its own title, meta description, and canonical tag written into the HTML, since SPAs often reuse one title for every page when the document head never updates on client-side navigation. URLs should be real paths like /pricing rather than hash routes like /#/pricing, because crawlers handle the fragment badly while the History API gives each page a clean path that returns real HTML on a direct load. The markup itself should be semantic, with headings in order, one h1 per page, and landmark elements, instead of the nested divs that generated code tends to produce.
Keep the primary content in the initial DOM too, rather than behind accordions, tabs, and read-more toggles, since text that only appears after a click can be discounted or skipped. Generated sites also tend to ship neither a sitemap.xml nor a working robots.txt, and the sitemap matters more than it looks, because Vercel's analysis of Google's indexing process found an updated sitemap removes most of the discovery delay between client and server rendering. Bing deserves the same attention, since it leans on IndexNow, the real-time submission protocol Microsoft co-developed, which can cut the gap between publishing a page and Bing indexing it from days to minutes, and that speed feeds straight through to ChatGPT.
Performance is the last piece. Large JavaScript bundles drag down LCP and INP, while unsized images and late-loading fonts cause layout shift, so code-split the bundle, lazy-load below the fold, compress images, and reserve space for anything that loads in.
Getting cited in ChatGPT, Claude, and Perplexity
Ranking in Google and getting cited in an AI answer run on different signals, so clearing the rendering fix only gets the AEO work started. A few things decide whether an engine can actually use your page as a source.
Everything that matters has to live in the raw HTML. The cost is higher here than for Google, because there is no second render to save you, so the definitions, steps, prices, and comparisons all have to be in the first response. JSON-LD structured data has to be server-rendered for the same reason, since schema injected by JavaScript is as invisible to a non-rendering crawler as body text is. Put your Article, Organization, Product, FAQPage, and BreadcrumbList markup in the initial HTML, where clean JSON-LD also helps ClaudeBot and others classify and attribute what they read. Your robots.txt then has to allow the AI crawlers by name, because blocking them drops you out of the answers completely, and a permissive file looks like this.
User-agent: GPTBot
Allow: /
User-agent: OAI-SearchBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: Claude-SearchBot
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: Google-Extended
Allow: /
Beyond the plumbing, a few content habits decide how often you get quoted. An llms.txt file at the root gives AI systems a clean map of your most important pages, and while adoption is still early, it costs almost nothing to add. Answer-shaped content helps even more, which means using questions as headings, putting a direct answer in the first sentence under each, and keeping sections short and self-contained, because content buried three scrolls down rarely gets surfaced. Entity clarity ties it together, so a consistent name, a clear description, and sameAs links to your real profiles make it easier for an AI system to attribute a claim to you rather than to a competitor with a cleaner footprint.
A pre-launch checklist
Before a vibe coded site goes live, these eight checks settle whether it can be found at all. Run them as a gate before launch, because every item maps to a specific way the site goes invisible.
- Content appears in View Page Source with JavaScript disabled
- Each route has a unique title, description, and canonical
- URLs are clean paths, not hash fragments
- One h1 per page, headings in order, primary content in the initial DOM
- sitemap.xml and a permissive robots.txt are present
- JSON-LD is server-rendered, not injected by a script
- The AI crawlers are allowed in robots.txt
- LCP, CLS, and INP pass on mobile
If a site fails the first item, the rest barely matter, so fix the rendering before you spend a minute on the others. Once that first check passes, the remaining seven are an afternoon of work rather than a rebuild.
A prompt to paste into your builder
All of this is far cheaper to get right in the first prompt than to retrofit after launch, so we keep a standing block of instructions that we paste into Lovable, Bolt, v0, or Replit, or drop into a Cursor rules file, before a build even starts. It tells the tool to render on the server and ship the technical basics up front, which heads off most of what this post describes. Copy it, swap in your own product details, and send it along with whatever you are asking the builder to make.
Build this as a server-rendered site, not a client-side-only SPA.
Rendering
- Use a framework that returns full HTML on the first request
(Next.js, Astro, SvelteKit, Nuxt, or TanStack Start). For
marketing, blog, and docs pages, statically generate them at build time.
- All primary content must be in the raw HTML before any JavaScript runs.
Do not hide main content behind tabs, accordions, or "read more" toggles
in a way that keeps it out of the initial DOM.
Routing and metadata
- Use clean path-based URLs like /pricing, never hash routes like /#/pricing.
- Give every route its own unique title, meta description, and canonical
tag rendered into the HTML.
- Use semantic HTML with one h1 per page, headings in order, and landmark
elements (header, nav, main, footer).
Structured data and crawler access
- Add server-rendered JSON-LD (Organization, Article or Product,
BreadcrumbList, and FAQPage where relevant). Do not inject schema with
client-side JavaScript.
- Generate sitemap.xml and robots.txt. The robots.txt must allow GPTBot,
OAI-SearchBot, ClaudeBot, Claude-SearchBot, PerplexityBot, Google-Extended,
and Bingbot.
- Add an llms.txt file at the root linking the most important pages.
Performance
- Keep LCP, CLS, and INP passing on mobile. Code-split the bundle, lazy-load
below-the-fold assets, set explicit width and height on images, and
preload fonts.
After building, confirm the homepage and one inner page show full content
in View Page Source with JavaScript disabled.
Adapt the framework line to whatever your tool defaults to, since there is no point pushing v0 toward Astro when its Next.js default already server-renders. Once the build is done, run the three checks from earlier on the live pages. A prompt sets the intent, and the page source tells you whether the tool actually followed it.
Where this is heading
The order matters more than any single tactic. Rendering decides whether everything else can work, which puts it in the first prompt rather than a cleanup pass after launch. A client-rendered SPA can be migrated later, but a rewrite costs far more than asking for SSR on day one, and the builders moving to server rendering by default show where the category is going.
Vibe coding keeps getting better at this, with v0 server-rendering out of the gate and Lovable shipping SSR plus pre-rendering as defaults, so the baseline is rising fast. For now, the difference between a site that ships and a site that gets found is still the rendering layer, and it pays to close that gap before the traffic you planned for fails to show up. If you want to see how your own vibe coded site reads to ChatGPT, Claude, and Perplexity today, our free AI Visibility Audit shows you exactly what those engines see, and you can talk to us about fixing it.
See where your brand stands in AI answers today, benchmarked against your competitors, no pitch required.

The Brand Risk Almost Nobody Is Defending In AI Search
AI tools can repeat a wrong or hostile claim about your brand to every buyer who asks. Here is how the attacks work and how to defend the narrative.
read_post →
Most AI answers in Bahasa Indonesia are thin, and local brands can own the gap
Ask an AI assistant the same question in English and Bahasa Indonesia and the Indonesian answer is thinner, drawn from fewer sources. That gap is the biggest first-mover opening in search, and here is how to take it.
read_post →
Google ignores IndexNow, which is exactly why it is worth setting up
IndexNow gets dismissed because Google won't use it, but Bing, Yandex, Naver, Seznam and Yep do, and Bing's index feeds Copilot, DuckDuckGo and ChatGPT search. A full implementation guide across WordPress, Shopify, Cloudflare and headless, plus measurement.
read_post →