← All framework guides

Vue.js SEO: 6 checks and how to fix them

These are the Vue.js-specific checks RankCLI runs, and the fix for each one in Vue.js's own idiom. Vue.js renders on the client by default, which is where most of its SEO problems come from.

6 checks
2 rated error
spa
Client-rendered by default

Run all of these against your own site, free and without an account:

npx @rankcli/cli audit -u https://your-site.dev

Where Vue.js makes SEO harder

  • •Client-side rendering sends empty HTML to crawlers
  • •Vue Router requires proper server configuration
  • •Async components delay content rendering
  • •No built-in meta tag management

The checks

error
VUE_CSR_DETECTED

Client-side rendered Vue app detected

Vue apps without SSR send empty HTML to crawlers.

Option 1: Migrate to Nuxt for automatic SSR/SSG Option 2: Add SSR with @vue/server-renderer Option 3: Use prerendering with prerender-spa-plugin

For Nuxt migration, most Vue components work directly.

error
VUE_NO_META_MANAGEMENT

No meta tag management library

Title and meta description are not dynamically managed.

Install @vueuse/head or vue-meta:

npm install @vueuse/head
// main.ts
import { createHead } from '@vueuse/head';
const head = createHead();
app.use(head);
<script setup>
import { useHead } from '@vueuse/head';

useHead({
  title: 'Page Title',
  meta: [
    { name: 'description', content: 'Page description' },
  ],
});
</script>
warning
VUE_ROUTER_HISTORY_MODE

Vue Router not in history mode

Hash mode (#/) creates ugly URLs and SEO issues.

Use createWebHistory instead of createWebHashHistory:

import { createRouter, createWebHistory } from 'vue-router';

const router = createRouter({
  history: createWebHistory(),
  routes: [...],
});

Then configure your server to return index.html for all routes.

warning
VUE_ASYNC_COMPONENT_NO_LOADING

Async components without loading state

Async components can cause CLS when they pop in.

Provide a loading component:

import { defineAsyncComponent } from 'vue';

const AsyncComp = defineAsyncComponent({
  loader: () => import('./HeavyComponent.vue'),
  loadingComponent: LoadingSpinner,
  delay: 200,
});
notice
VUE_NO_KEY_ON_LIST

v-for without :key attribute

Missing keys can cause rendering issues and affect SEO crawling.

Always use :key with v-for:

<div v-for="item in items" :key="item.id">
  {{ item.name }}
</div>
notice
VUE_TRANSITION_CLS

Transitions may cause layout shifts

CSS transitions that change element size cause CLS.

Use transform instead of width/height changes:

/* Bad - causes CLS */
.fade-enter-active { height: 0 to 100px; }

/* Good - no CLS */
.fade-enter-active { transform: scaleY(0) to scaleY(1); }

Check your own Vue.js site

280+ checks including every one above. No signup, nothing leaves your machine.

Run a free audit