Vue und SEO

Vue 3 standardmäßig Client-Side Rendering verwendet, daher ist der Inhalt nicht im rohen HTML. So machen Sie Vue-Apps crawlbar und indexierbar – Router-Modus, @unhead/vue, Prerendering mit vite-ssg, SSR/SSG mit Nuxt, Hydration und Core Web Vitals.

Erstveröffentlicht: 26. Juni 2026 · Zuletzt aktualisiert: 3. Aug. 2026 · Fortgeschritten
Sprachen

Vue 3 verwendet standardmäßig Client-Side Rendering, daher liefert eine einfache Vite + Vue-App eine leere HTML-Hülle und erstellt die Seite im Browser. Google kann sie rendern – aber das Rendering ist verzögert und asynchrone Daten können übersehen werden, und Bing und Social-Scraper können das JS oft gar nicht ausführen. Die Lösungen: Verwenden Sie den Vue-Router im History-Modus (nicht im Hash-Modus), verwalten Sie <head> mit @unhead/vue, und bringen Sie den Inhalt mit Prerendering (vite-ssg), SSR oder SSG über Nuxt ins HTML. Dynamisches Rendering ist veraltet – bauen Sie nicht darauf auf.

TL;DR — Vue 3 ist standardmäßig CSR, daher ist der Inhalt nicht im rohen HTML – Google rendert es später über seine Evergreen-Chromium-WRS, aber das Rendering wird in die Warteschlange gestellt und asynchrone Daten, die in onMounted abgerufen werden, können übersehen werden, und Bing/Social-Scraper führen das JS oft gar nicht aus. Nicht verhandelbar: Vue Router createWebHistory() (Hash-Modus hat “einen schlechten Einfluss auf SEO”), <head> über @unhead/vue / useSeoMeta(), und eine Rendering-Strategie, die Inhalte ins HTML bringt – vite-ssg-Prerendering für inhaltsstabile Websites, Nuxt für vollständiges SSR/SSG. Dynamisches Rendering ist veraltet; prerender-spa-plugin ist Legacy. Achten Sie auf Hydration-Mismatches (eine Server/Client-Inhaltsdifferenz ist ein SEO-Problem, nicht nur ein Performance-Problem) und die Auswirkung des CSR-Bundles auf LCP. Für die framework-agnostische Version all dessen, siehe JavaScript SEO.

Das Standard-Vite-+-Vue-Gerüst ist client-seitig gerendert

Eine einfache npm create vue@latest-App (Vite + Vue) liefert eine fast leere HTML-Hülle und ein JavaScript-Bundle. Der Browser führt dieses Bundle aus, um das DOM aufzubauen. Das ist für Nutzer in Ordnung, aber ein Problem für Crawler: Das rohe HTML enthält fast keinen Inhalt, und alles hängt vom Rendering ab.

Das ist eine Eigenschaft des Standard-Scaffolds, keine Grenze von Vue selbst – Vue Core unterstützt auch Server-Rendering (createSSRApp) und statische Generierung als erstklassige Pfade, und Vues eigener SSR-Leitfaden lenkt die meisten Produktions-SSR/SSG-Arbeiten eher zu Nuxt als zu einem handgebauten Setup. Bevor Sie also zu einer Lösung greifen, prüfen Sie, was Ihre App tatsächlich ausliefert: Eine nackte Vite-SPA ohne Rendering-Konfiguration ist CSR; dieselbe App hinter Nuxt oder vite-ssg ist es nicht.

Vues eigener SSR-Leitfaden ist direkt, was den Vorteil angeht, dies nicht zu tun: Mit Server-Side-Rendering “the search engine crawlers will directly see the fully rendered page.” (Übersetzung) „Die Suchmaschinen-Crawler sehen die vollständig gerenderte Seite direkt.“ Die Kehrseite ist das, was Sie standardmäßig ausliefern – Inhalte, die erst existieren, nachdem JavaScript läuft. Evidence for this claim Vue server-side rendering sends rendered HTML so crawlers can directly see page content. Scope: Vue SSR benefits; does not guarantee indexing. Confidence: high · Verified: Vue: SSR guide

(Vue 2 erreichte im Dezember 2023 das Ende seiner Lebensdauer; hier geht es alles um Vue 3.)

Wie Googlebot eine Vue-App verarbeitet

Google verarbeitet JavaScript in Phasen – das rohe HTML wird gecrawlt, dann in einer Evergreen-Headless-Chromium-Instanz (dem Web Rendering Service) gerendert, und dann wird das gerenderte Ergebnis indexiert. Daraus folgen zwei Dinge:

  • Rendering wird in eine Warteschlange gestellt und verzögert. Eine Seite sitzt in der Render-Warteschlange – normalerweise Sekunden bis Minuten, aber es kann auch ausschlagen. Inhalte, die erst nach der JS-Ausführung existieren, sind nicht sofort indexierbar; Inhalte im rohen HTML sind es.
  • Asynchrone Daten sind das eigentliche Risiko. Synchrones JavaScript rendert zuverlässig. Daten, die nach dem Mounten von einer API geholt werden, sind nicht garantiert erfasst. Vues SSR-Leitfaden sagt es deutlich: “If your app starts with a loading spinner, then fetches content via Ajax, the crawler will not wait for you to finish. This means if you have content fetched asynchronously on pages where SEO is important, SSR might be necessary.” (Übersetzung) „Wenn Ihre App mit einem Lade-Spinner startet und dann Inhalte per Ajax abruft, wartet der Crawler nicht, bis Sie fertig sind. Das bedeutet: Wenn Sie Inhalte asynchron auf Seiten abrufen, bei denen SEO wichtig ist, könnte SSR notwendig sein.“ Praktisch: Daten, die in onMounted abgerufen werden, sind nur clientseitig und für Crawler, die nicht rendern, unsichtbar – und selbst bei denen, die es tun, riskant.

John Mueller hat den Fehlermodus für SPA-artige Setups beschrieben, bei denen das statische HTML weitgehend identisch ist und alle einzigartigen Inhalte von JavaScript abhängen: Wenn dieses JS nicht ordnungsgemäß ausgeführt werden kann, sehen die Seiten für Google gleich aus, und der Fokus bleibt auf dem Boilerplate-HTML statt auf den JS-geladenen Inhalten. Die Lektion ist dieselbe wie auf der breiteren JavaScript-SEO-Seite: Bringen Sie die Inhalte schnell und zuverlässig ins DOM.

Bing und Social-Bots sind dabei schlechter als Google. Bing hat keine mit Google vergleichbare Rendering-Pipeline, und Social-Preview-Scraper (X, Slack, iMessage) führen im Allgemeinen überhaupt kein JavaScript aus – eine nackte CSR-Vue-App erzeugt also leere Share-Previews. Wenn Bing-Traffic oder Social-Sharing wichtig ist, sind Prerendering oder SSR nicht optional.

Vue Router: createWebHistory() verwenden, nicht den Hash-Modus

Vue Router hat zwei Verlaufsmodi. Hash-Modus (createWebHashHistory()) erzeugt URLs wie example.com/#/about; die Vue-Router-Dokumentation sagt, dass er “does however have a bad impact in SEO” (Übersetzung) „jedoch einen schlechten Einfluss auf SEO hat“, weil alles nach dem # ein Fragment ist, das der Server ignoriert. Evidence for this claim Vue Router hash history uses a URL fragment that is not sent to the server and is discouraged for SEO. Scope: Vue Router hash history. Confidence: high · Verified: Vue Router: History modes Verwenden Sie den HTML5-Verlaufsmodus:

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

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

Der Verlaufsmodus ergibt saubere URLs (example.com/about), erfordert aber einen Server-Fallback – jede direkte Anfrage an eine Route muss index.html ausliefern, damit Vue übernehmen kann, sonst führen direkte Treffer zu 404. Konfigurieren Sie diesen Catch-all auf Ihrem Host (Nginx try_files, ein SPA-Rewrite auf Netlify/Vercel/Cloudflare usw.).

Begrenzen Sie dieses Rewrite sorgfältig – ein Catch-all, der zu breit ist, liefert auch index.html für fehlende statische Assets, echte API-Routen oder Seiten aus, die Sie tatsächlich als 404 haben möchten. Das macht die Soft-404-Anleitung unten stillschweigend zunichte und kann einen kaputten Link hinter einer Seite verstecken, die aussieht, als hätte sie „funktioniert“.

Für echte Nicht-gefunden-Zustände vermeiden Sie Soft-404s – eine clientseitige „Nicht gefunden“-Ansicht, die weiterhin 200 zurückgibt, kann als leere Hülle indexiert werden. Die Anleitung von Google lautet, entweder auf eine URL umzuleiten, die einen echten 404-Status zurückgibt, oder ein <meta name="robots" content="noindex"> zu Fehlerseiten hinzuzufügen, und die History API für das Routing zwischen Ansichten zu verwenden.

Head- und Meta-Verwaltung: @unhead/vue

Standardmäßig teilen sich alle Vue-Routen einen <title> und eine Meta-Description. Die Tag-Historie ist hier wichtig, weil die alten Antworten Sackgassen sind:

  • vue-meta – die Bibliothek aus der Nuxt-2-Ära. Veraltet.
  • @vueuse/head – ihr Nachfolger, inzwischen eingestellt.
  • @unhead/vue – der aktuelle Community-Standard und das, was Sie für eine Nicht-Nuxt-Vue-3-App verwenden sollten.

Der ergonomische Einstiegspunkt ist das useSeoMeta()-Komposable – typsicher, XSS-sicher und mit Kenntnis von über 100 Meta-Tags, einschließlich Open Graph und Twitter Card:

import { useSeoMeta } from '@unhead/vue'

useSeoMeta({
  title: 'Vue SEO Guide',
  description: 'How to make a Vue 3 app crawlable and indexable.',
  ogTitle: 'Vue SEO Guide',
  ogDescription: 'How to make a Vue 3 app crawlable and indexable.',
  twitterCard: 'summary_large_image',
})

Meta kann reaktiv sein – übergeben Sie einen Getter oder einen berechneten Wert, und die Tags aktualisieren sich, wenn sich Ihre Daten ändern. Für kanonische Tags ist das sicherste Muster immer noch HTML, nicht JS: Die Anleitung von Google besagt, dass “the best way to set the canonical URL is to use HTML,” und wenn Sie es mit JavaScript injizieren müssen, setzen Sie es immer auf denselben Wert, den das HTML hätte. (Ich habe JS-Kanonische bei Ahrefs getestet und festgestellt, dass Google sie respektiert – es führte sogar dazu, dass Google eine Ausnahme zu seiner Dokumentation hinzufügte – aber HTML ist immer noch der risikoärmere Weg.)

Wählen Sie eine Rendering-Strategie

Dies ist die Entscheidung, die wirklich den Unterschied macht. Gleiches Menü wie auf der framework-agnostischen JavaScript-SEO-Seite, angewendet auf Vue.

Client-seitiges Rendering (CSR) – der Standard und der riskante. Akzeptabel für app-ähnliche Seiten hinter einem Login, Dashboards und alles, was nicht indexiert werden muss. Nicht akzeptabel für Inhalte, die ranken oder geteilt werden müssen.

Prerendering mit vite-ssg. Für inhaltsstabile Vue-3-SPAs generiert vite-ssg statisches HTML zur Build-Zeit – tauschen Sie Ihr Build-Skript von vite build auf vite-ssg build. Es enthält @unhead/vue integriert. Großartig für Marketing-Websites, Dokumentationen und Blogs; kein Ersatz für SSR auf stark dynamischen, pro Anfrage generierten Seiten. Beachten Sie, dass das alte webpack-zeitliche prerender-spa-plugin veraltet und praktisch nicht mehr gewartet istvite-ssg (oder Nuxt) ist der moderne Ersatz.

Server-seitiges Rendering. Der offizielle Vue-Leitfaden behandelt ein manuelles SSR-Setup mit @vue/server-renderer, lenkt die meisten Projekte jedoch ausdrücklich zu einem Meta-Framework, anstatt ein eigenes zu entwickeln – und für einfache Fälle sagt er sogar “if you’re only investigating SSR to improve the SEO of a handful of marketing pages … then you probably want SSG instead of SSR.” Wenn Sie manuelles SSR durchführen, erstellen Sie App, Router und Store pro Anfrage neu: Auf einem langlebigen Node-Server werden Modulebene-Singletons über Anfragen hinweg wiederverwendet, und das Mutieren von gemeinsamem Zustand mit den Daten eines Benutzers kann diese in die Antwort eines anderen Benutzers leaken. Das ist ein weiterer Grund, warum die Vue-Dokumentation die meisten Projekte auf Nuxt verweist, das die Isolierung pro Anfrage für Sie übernimmt.

Evidence for this claim Module-scope singleton state in Vue SSR can leak user-specific data across requests; create application, router and store instances per request. Scope: SSR and hydration Confidence: high · Verified: Server-Side Rendering

Nuxt – die empfohlene Komplettlösung. Nuxt bietet SSR und SSG out of the box, integriertes useSeoMeta() und Head-Management sowie das @nuxtjs/seo-Modul für Sitemaps, robots.txt und strukturierte Daten. Für die meisten Vue-Projekte, bei denen SEO wichtig ist, ist dies der Weg, den Vues eigene Dokumentation aufzeigt. (Nuxt hat seine eigene Tiefe – separat behandelt; betrachten Sie dies als Querverweis, nicht als tiefen Einblick.)

Dynamisches Rendering – nicht tun. Das Ausliefern von vorgerendertem HTML an Bots und der SPA an Benutzer war immer ein Workaround, und Google hat es 2024 als veraltet eingestuft, wobei die Implementierungsdokumentation entfernt wurde. Bauen Sie stattdessen auf SSR oder SSG auf.

Für Dokumentationen im Speziellen ist VitePress der Vue-native Static-Site-Generator. Jede Seite wird als reines HTML ausgeliefert – keine JS-Rendering-Barriere – und SEO wird über Frontmatter (title, description, head) oder den transformHead-Build-Hook für kanonische/dynamische Tags konfiguriert.

Hydratationsabweichungen sind ein SEO-Problem, nicht nur ein Performance-Problem

Wenn Sie SSR/SSG verwenden, mountet der Client mit createSSRApp() – nicht mit dem einfachen createApp() – und hydratisiert das serverseitig gerenderte HTML, anstatt es von Grund auf neu aufzubauen. Wenn das Server-HTML und das Client-Rendering divergieren, verwirft Vue die abweichenden Knoten und rendert sie neu. In SEO-Begriffen bedeutet das, dass der Inhalt, den Google aus dem Server-Rendering indexiert hat, von dem abweichen kann, was der Benutzer nach der Hydratation sieht – eine Inkonsistenz im Qualitätssignal, nicht nur ein Flackern. Häufige Ursachen: ungültiges HTML-Verschachteln, zufällige Werte in Vorlagen und Datums-/Zeitabweichungen zwischen Server und Client. Vue 3.5+ fügt data-allow-mismatch hinzu, um die Warnung über die Abweichung selektiv zu unterdrücken, wo eine Abweichung beabsichtigt ist – es beruhigt die Konsole, macht aber die Server- und Client-Ausgabe nicht äquivalent. Greifen Sie also nicht einfach danach, um eine Abweichung zu verstummen, die Sie nicht tatsächlich diagnostiziert haben.

Core Web Vitals sind ein Vue-spezifisches Anliegen

Standard-CSR-Vue liefert ein großes JS-Bundle, das heruntergeladen, geparst und ausgeführt werden muss, bevor der größte Inhalt gemalt wird – also leidet LCP, wenn Sie nichts tun. Hebel:

  • Code-Splitting (Vite-Standard) und lazy-loaded Routen, damit Sie nicht die gesamte App im Voraus ausliefern.
  • fetchpriority="high" auf dem LCP-Heldenbild.
  • Vapor Mode – ein optionaler Compiler-Modus, der für geeignete Komponenten das virtuelle DOM umgeht, was die Hydratationskosten auf SSR-Seiten senken kann. Es ist Vue 3,6, nicht 3,5 – noch experimentell (Beta/Release-Kandidat ab Mitte 2026, noch nicht in der stabilen 3,5.x-Linie) – es ist beobachtenswert, aber nichts, worauf man heute in der Produktion angewiesen sein sollte.

Strukturierte Daten in Vue

Google führt JavaScript aus, bevor es strukturierte Daten liest, daher funktioniert das Einfügen von JSON-LD – @unhead/vue’s useHead() mit einem script vom Typ application/ld+json ist das zuverlässige Muster. Da es vom Rendering abhängt, bestätigen Sie es mit URL Inspection, anstatt anzunehmen, dass Google es gesehen hat.

Wo dies einzuordnen ist

Vue-SEO ist ein Beispiel für das allgemeine JavaScript-SEO Problem – Parität, Interaktion, Zustand, Timing – und es teilt fast alles mit der Headless-CMS Situation, bei der der Rendering-Modus des Frontends das Ergebnis bestimmt.

Eine Einschränkung, die für jede der oben genannten Optionen gilt: SSR und SSG bringen Ihre Inhalte in das HTML, aber keines von beiden garantiert Indexierung, Rankings, Core Web Vitals oder dass die Hydratation exakt mit der Server-Ausgabe übereinstimmt. Sie entfernen die JavaScript-Rendering-Barriere – der Rest der SEO (und Korrektheit) liegt weiterhin bei Ihnen.

Wenn Sie sich eines merken: Bringen Sie Ihre Inhalte ins HTML. Alles andere ist Detail.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.