Guide · 10 min read

v0 SEO: get your v0 site found on Google

For people who built a site with Vercel's v0 and want it found. What v0 gets right, the five gaps to close, prompts for v0's chat and for a coding agent, and how to check each one.

Updated · By the Serpkin team

In short

  • v0 generates Next.js App Router projects with Server Components, so pages are usually server-rendered HTML that Google can read.
  • The common gaps are one title for every page, no canonical, no sitemap or robots.txt, and the vercel.app host serving duplicate pages.
  • Redirect your vercel.app host to your domain with a host-scoped permanent redirect, and set metadataBase plus per-page canonicals.
  • Watch for pages whose content moved into a client component with useEffect; curl each page type after big chats.
  • v0's GitHub sync is two-way, so larger SEO work can happen in the repo with a coding agent and come back through Pull Changes.

A site built with v0 starts in a good place for Google. v0 generates a Next.js App Router project, uses Server Components, and deploys to Vercel, so pages usually arrive as real server-rendered HTML. The gaps are the parts nobody asks for in a chat: a title and description per page instead of one in the layout, a canonical, a sitemap and robots.txt, the vercel.app address competing with your domain, and the occasional page whose content was moved into a client component. Fix your domain and canonicals first, then per-page metadata, then the sitemap. Everything here is standard Next.js, so the fixes are short. For the platform-wide picture, see SEO for AI-built websites.

What v0 builds and how it renders

v0 output and hosting, per v0 and Vercel docs (October 2026)
QuestionAnswerSEO meaning
FrameworkNext.js by default (other frameworks possible, less reliable per v0's docs)Server rendering and the Metadata API are available
RenderingApp Router with Server Components; Vercel says v0 sites are server-rendered by defaultContent is in the HTML unless a page moves it into the browser
HostingVercel, with a vercel.app URL for every deploymentOne more host serving your pages
PreviewsA working branch and preview deployment per chatVercel adds X-Robots-Tag: noindex to previews
SEO page in the docsNone; Vercel's blog describes metadata, Open Graph and JSON-LD supportAsk for SEO work explicitly

The risk on v0 is not the framework, it is drift. A chat that adds a carousel, a filter or a data fetch can turn a page into "use client" with a useEffect, and the copy that used to be in the HTML now only appears in the browser. That is why the diagnosis below checks every page type, not just the home page.

The five-minute diagnosis

  1. Curl your production pages
    Terminal
    for p in / /pricing /about /blog/first-post; do
      echo "== $p"
      curl -s "https://your-domain.com$p" | grep -oE '<title>[^<]*|<h1[^>]*>[^<]*|<link rel="canonical"[^>]*>'
    done
    Terminal
    $ for p in / /pricing /blog/first-post; do …; done
    == /
    <title>v0 App
    <h1>Plan your week in minutes
    == /pricing
    <title>v0 App
    <h1>Pricing
    == /blog/first-post
    <title>v0 App
    (no h1, no canonical)
    
    Illustrative output. The same title on every page and no canonical: metadata lives only in app/layout.tsx. The blog post's H1 is missing because the post loads in a client component.

    Good output has a different title per page, an H1 on every page, and a canonical on your domain. Next.js streams metadata on dynamic pages, so the title can appear late in the body for normal clients; Google reads it there.

  2. Check the vercel.app address
    Terminal
    curl -sI https://your-project.vercel.app/pricing | grep -iE "^(HTTP|location|x-robots-tag)"

    If this returns 200 with no noindex and no redirect, Google can index the same pages on two hosts. The redirect checker shows the chain.

  3. Check robots.txt, the sitemap and 404s
    Terminal
    curl -s https://your-domain.com/robots.txt
    curl -sI https://your-domain.com/sitemap.xml | head -1
    curl -s -o /dev/null -w "%{http_code}\n" https://your-domain.com/blog/does-not-exist

    You want a robots.txt that names your sitemap, a 200 sitemap and a 404 for the missing post. The free SEO checker covers one URL end to end.

Fixes, in order of impact

  1. 1One hostCustom domain; vercel.app redirects to it
  2. 2Server HTMLMain content in Server Components
  3. 3MetadatametadataBase, per-page title, description, canonical
  4. 4Sitemap + robotsapp/sitemap.ts and app/robots.ts
  5. 5Status codesnotFound() for missing records
Fix order for a v0 site: one host first, so every later signal points at the right URL.

1. Put the site on your domain, and only there

In v0, add a domain from Publish, Customize Domain (or the project's Settings, Domains); DNS and redirects are managed in the Vercel dashboard. Then redirect the vercel.app host. Vercel's guide recommends a host-scoped permanent redirect in vercel.json:

vercel.json
{
  "redirects": [
    {
      "source": "/(.*)",
      "has": [{ "type": "host", "value": "your-project.vercel.app" }],
      "destination": "https://your-domain.com/$1",
      "permanent": true
    }
  ]
}

Previews stay safe on their own: Vercel adds X-Robots-Tag: noindex to every preview deployment, unless you assign a custom domain (such as staging.your-domain.com) to a non-production branch. Noindex those yourself.

2. Keep the main content in Server Components

If a page lost its H1 or copy in the curl check, ask v0 to move the data back to the server:

Prompt for v0
On /blog/[slug], fetch the post in the page (a Server Component) and pass it to the
client components as props. Keep "use client" only on the interactive parts (the like
button and the share menu). The post title must be the page's only <h1>. Don't change
the design.

3. Give every page its own metadata

v0 often sets one metadata object in app/layout.tsx and stops there. Set metadataBase and a title template in the layout, then a title, description and canonical per page (generateMetadata for dynamic routes). Never put the canonical in the layout, or every page inherits the homepage's.

app/layout.tsx
export const metadata: Metadata = {
  metadataBase: new URL("https://your-domain.com"), // never the vercel.app or a preview URL
  title: { default: "Acme", template: "%s | Acme" },
  description: "Plan your week in minutes. Free for teams of up to five.",
};
app/pricing/page.tsx
export const metadata: Metadata = {
  title: "Pricing",
  description: "Acme is free for up to five people. Paid plans add unlimited projects, SSO and priority support.",
  alternates: { canonical: "/pricing" },
};

Preview titles and descriptions with the SERP preview. Our Next.js SEO checklist covers metadata merging, Open Graph images and hreflang in more depth.

4. Add a sitemap and robots.txt

Prompt for v0
Add app/sitemap.ts that returns every public route as an absolute URL on
https://your-domain.com (blog posts from the same data source the blog uses, with
lastModified from the post's real update date). Add app/robots.ts that allows everything
except /api/ and points to the sitemap. Don't disallow /_next/.

Check both after deploying with the robots.txt tester and sitemap validator.

5. Return real 404s

Pages for records that don't exist should call notFound(). It only sets a 404 status if it runs before streaming starts, so if the route has a loading.tsx, check that the record exists before any Suspense boundary. Otherwise the page returns 200 with a noindex tag.

Working on the code outside v0

Larger SEO changes (a sitemap from a CMS, redirects for renamed URLs, structured data across templates) are easier in a repo with a coding agent. v0's GitHub sync is two-way: once connected, the repository is the source of truth. Each chat works on its own branch with its own preview deployment, and Publish opens or reuses a pull request into your base branch. Pull Changes brings commits made outside v0 back in.

  1. Connect GitHub in v0 and clone the repo

    Branch protection on the repo still applies to v0's pull requests.

  2. Brief your agent with checks it can run
    Prompt for a coding agent
    This Next.js App Router project was generated by v0 and deploys to Vercel.
    1. Add metadataBase (https://your-domain.com), a title template, and per-page title,
       description and alternates.canonical. Use generateMetadata on dynamic routes.
    2. Add app/sitemap.ts and app/robots.ts from the real routes.
    3. Move any main content fetched in useEffect into Server Components.
    4. Add the host-scoped vercel.app redirect to vercel.json.
    Done when curl on the preview deploy shows a unique <title>, an <h1> and a canonical on
    each route, and /blog/does-not-exist returns 404.
  3. Check the preview, merge, then pull in v0

    Curl the preview URL before merging. After the merge, use Pull Changes in v0 so the next chat starts from the fixed code.

What you can and can't control

SEO controls on a v0 project
ItemWhereNotes
Title, description, canonical, Open GraphNext.js Metadata API in each page.tsxFull control
robots.txt and sitemapapp/robots.ts, app/sitemap.tsNot created unless you ask
Path redirectsnext.config or vercel.jsonPermanent redirects are 308s
Domain redirectsVercel dashboard or vercel.jsonDashboard redirects may be temporary; check the status
404 statusnotFound()Before any Suspense boundary
Preview noindexVercel defaultExcept custom domains on non-production branches

Because v0 output is Next.js, npx serpkin maps its routes to files exactly: it sets up Claude Code, Codex or Cursor in the cloned repo, registers the site, runs a first scan and shows the first mission with the files to change. Small metadata fixes come bundled as one "Fix the basics" mission. Since v0 gives every chat a preview deployment, npx serpkin check <preview-url> is a natural gate before Publish: it fails if a preview drops a title, canonical or sitemap.

Check a page nowFree: see what a crawler finds on any URL, with a prompt for your agent.

Questions

Is v0 good for SEO?

Its output is a good starting point: Next.js with Server Components, rendered on the server and hosted on Vercel. You still need per-page titles, descriptions and canonicals, a sitemap, robots.txt and one canonical host.

Does v0 use server-side rendering?

Yes, by default. v0 builds Next.js App Router projects with Server Components, and Vercel says v0 sites return full HTML at request time. Content fetched inside a client component with useEffect is the exception.

How do I add a sitemap to a v0 site?

Ask v0 to create app/sitemap.ts that returns every public URL on your domain, and app/robots.ts that points to it. Next.js serves them at /sitemap.xml and /robots.txt.

Will Google index my vercel.app URL?

It can, because production vercel.app URLs serve the same pages without noindex. Add a host-scoped permanent redirect from the vercel.app host to your domain and use absolute canonicals on your domain.

Sources

Let your agent do the SEO work.

Serpkin finds the next fix from real search data, hands it to Claude Code, Codex or Cursor, and checks it after you ship.

npx serpkin
Start free