Vue SEO
Last reviewed
A Vue app created with npm create vue@latest is a single page application: the browser builds the page with JavaScript, and the major AI crawlers do not run it. To send crawlers finished HTML, use a framework with server rendering or prerendering such as Nuxt, prerender pages at build time, or put a prerender service in front of the existing app.
What GPTBot sees
<body> <div id="root"></div> <script src="/app.js"> </body>0 words
With Prebaked
Example page. Bots and people get the same content: the page your visitors' browsers already build.
At a glance
| Approach | Fixes content for AI crawlers | Fixes titles and meta tags | Effort | Best for |
|---|---|---|---|---|
Vue + Vite SPA (the create-vue default) |
No | Only for crawlers that run JavaScript | None | Apps behind a login |
| Nuxt universal rendering (SSR) | Yes | Yes | Migration to Nuxt, a server | New apps, apps you are rebuilding anyway |
Nuxt prerender: true route rules, or other SSG |
Yes, for routes known at build time | Yes | Medium | Marketing pages, docs, content that changes on deploy |
Meta tag libraries or document.title alone |
No | Only for crawlers that run JavaScript | Low | Managing tags together with one of the other options |
| Prerender service (Prebaked) | Yes | Yes | Low, one snippet | Existing Vue SPAs where a migration is not worth it |
Is Vue good for SEO?
Vue is neutral. What matters is whether crawlers get finished HTML.
- The default Vue project is a SPA. The official quick start says
create-vuescaffolds "a Vue Single Page Application" with "a build setup based on Vite". The server sends anindex.htmlwith an empty mount element. - Vue's own docs on search. The SSR guide says "Google and Bing can index synchronous JavaScript applications just fine", but "if your app starts with a loading spinner, then fetches content via Ajax, the crawler will not wait for you to finish." Its first reason for SSR is "Better SEO: the search engine crawlers will directly see the fully rendered page."
- Google queues pages for rendering, and a page "may stay on this queue for a few seconds, but it can take longer than that."
- AI crawlers do not render. Vercel and MERJ found that "none of the major AI crawlers currently render JavaScript".
So most Vue SPAs that load data from an API look empty to ChatGPT, Claude and Perplexity, and depend on rendering for Google. More on how AI crawlers see your site.
How to check your Vue app
- Run the free checker. It compares your page without JavaScript and in a real browser.
See what ChatGPT sees on your site
- Fetch the raw HTML of a deep route.
curl -s https://www.<your-domain>/products | grep -o '<div id="app">.\{0,80\}'
curl -s https://www.<your-domain>/products | grep -o "<title>.*</title>"
An empty <div id="app"></div>, or the same title on every route, means content and tags are added by JavaScript.
- For Google, use the URL Inspection tool in Search Console to see the rendered HTML.
Also check: Vue Router in history mode (createWebHistory), not hash mode, because Google says to "use the History API" and not fragments for different content. Use <RouterLink>, which renders an <a href>. Make the catch-all route return a 404 or add noindex.
Nuxt SEO: rendering modes
The Vue docs recommend a framework if you need SSR, because a complete SSR setup "would be quite complex", and list Nuxt, Vike, Astro and Quasar. They also say: "The general recommendation is to use a framework only if you need SSR."
Nuxt uses "universal rendering" by default: pages are rendered on the server and then hydrated in the browser. Crawlers get finished HTML.
Nuxt can also switch rendering per route with route rules:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// rendered once at build time
'/': { prerender: true },
'/pricing': { prerender: true },
// client-side only
'/admin/**': { ssr: false },
},
})
prerender "prerenders routes at build time and includes them in your build as static assets". ssr: false turns off server rendering for those routes, and setting ssr: false for the whole app makes it a client-rendered SPA. Nuxt's own docs note the cost: "Indexing and updating the content delivered via client-side rendering takes more time."
Choose Nuxt when you are starting a new Vue app or are ready to migrate. The cost for an existing Vue + Vite SPA is moving to Nuxt's file-based routing, data fetching and a server or platform that runs it.
Prerendering without SSR
The Vue docs call static site generation "also referred to as pre-rendering": pages are rendered "once, ahead of time, during the build process" and served as static HTML. They suggest it when you only need "a handful of marketing pages (e.g. /, /about, /contact, etc.)" to rank. VitePress, which builds the Vue docs, is a Vue-powered static site generator. Pages from live data are not covered until the next build.
Vue meta tags
In Nuxt
Nuxt has useHead and useSeoMeta. useSeoMeta "lets you define your site's SEO meta tags as an object with full type safety":
<script setup lang="ts">
useSeoMeta({
title: 'Pricing | Example',
description: 'Plans and prices.',
ogTitle: 'Pricing | Example',
})
</script>
Fixed values for the whole app go in app.head in nuxt.config.ts. With universal rendering the tags are part of the server-rendered HTML.
In a plain Vue SPA
Without a framework, titles and descriptions are set from JavaScript, for example in a Vue Router afterEach hook or with a head management library such as vue-meta. Google can pick them up after rendering. Crawlers that read only the raw HTML, including the major AI crawlers, see the tags in your static index.html on every route.
Use meta tag code together with server rendering, prerendering or a prerender service, not instead of them.
When a prerender service makes sense for Vue
A prerender service renders your pages in a real browser when a crawler asks and serves the HTML from a cache. People still get your Vue app. Google calls this dynamic rendering, "a workaround and not a long-term solution", and says that "Googlebot generally doesn't consider dynamic rendering as cloaking." The full explanation is on what is prerendering.
It fits when:
- you have a working Vue + Vite SPA and moving to Nuxt is not planned soon,
- pages come from an API and change between deploys, so build-time prerendering would be out of date,
- hosting is static (Netlify, Vercel, a CDN) and you do not want to run a server,
- the Nuxt app runs with
ssr: falsefor some or all routes that should be found in search.
If you are starting a new Vue app that needs search traffic, Nuxt with universal rendering or prerender rules is the better choice.
When Prebaked is the right choice
- One snippet: Netlify, Vercel, Cloudflare Worker, nginx or another integration.
- Same page for bots and people: Prebaked renders your page in Chromium and does not change its content.
- Never worse than today: if Prebaked is slow or down, crawlers get your original page.
- Status codes kept: a page that renders as a 404 returns 404. Your catch-all route can set it with
<meta name="prerender-status-code" content="404">. - Ready signal: set
window.prerenderReady = truewhen the data for a page has loaded. - Cache hits are free. You pay for fresh renders only. Warm the cache from your sitemap.
FAQ
Is Vue bad for SEO?
No. A client-rendered Vue SPA is the issue. Google can render it, but content loaded after a spinner may be missed, and AI crawlers do not run JavaScript at all. Nuxt, prerendering or a prerender service sends finished HTML.
Do I need Nuxt for Vue SEO?
Not always. Nuxt is the most complete option for new apps. For a few marketing pages, build-time prerendering is enough. For an existing Vue SPA, a prerender service gives crawlers finished HTML without a migration.
How do I add meta tags in Vue?
In Nuxt, use useSeoMeta or useHead in a page, and app.head in nuxt.config.ts for site-wide defaults. In a plain Vue SPA you set them from JavaScript, which crawlers that do not render will not see.
Does Nuxt prerender pages?
Yes, if you ask it to. A route rule with prerender: true renders that route at build time and ships it as static HTML. By default Nuxt renders on the server for each request.
Can ChatGPT see my Vue app?
If it is a client-rendered SPA, ChatGPT's crawlers get the HTML before JavaScript runs, which is often an empty <div id="app">. Check your page with the free checker.