React, Vue, Angular — moderne JavaScript-Frameworks haben die Web-Entwicklung revolutioniert. Single Page Applications (SPAs) sind reaktionsschnell, bieten native App-Feeling und begeistern Nutzer. Doch für Googles Crawler stellen sie eine besondere Herausforderung dar: Was passiert, wenn der Inhalt einer Seite erst nach JavaScript-Ausführung sichtbar wird?
In diesem Artikel erkläre ich, wie Googlebot JavaScript-basierte Websites crawlt, was Two-Wave Indexing bedeutet und welche Maßnahmen du ergreifen solltest, damit deine SPA korrekt indexiert wird.
Das Problem: Was Googlebot wirklich sieht
Stell dir vor, du öffnest eine React-App im Browser. Du siehst eine vollständig gerenderte Seite mit Produkten, Texten und Navigation. Aber wenn du den Quelltext (Strg+U) anschaust, siehst du oft nur das:
<!DOCTYPE html>
<html lang="de">
<head>
<title>Meine App</title>
</head>
<body>
<div id="root"></div>
<script src="/static/js/main.abc123.js"></script>
</body>
</html>
Das ist das fundamentale Problem: Der rohe HTML-Quelltext enthält keinen Inhalt. Alles — Produkttexte, Preise, Navigation, Meta-Tags — wird erst durch JavaScript erzeugt.
Nutze unseren JavaScript-SEO-Checker, um zu prüfen ob deine Website von diesem Problem betroffen ist.
Wie Googlebot JavaScript verarbeitet
Googlebot kann JavaScript ausführen — aber anders als dein Browser. Google verwendet ein sogenanntes Headless-Chrome-System, das JavaScript rendert, aber mit deutlichen Einschränkungen:
Two-Wave Indexing: Die zwei Phasen
Google indexiert JavaScript-Seiten in zwei Phasen:
- Wave 1 — HTML-Crawl: Googlebot lädt die rohe HTML-Datei und extrahiert alle direkt verfügbaren Inhalte. URLs werden für das Rendering in eine Warteschlange eingereiht.
- Wave 2 — JavaScript-Rendering: Seiten aus der Warteschlange werden mit Headless Chrome gerendert. Dieser Schritt kann Stunden bis Tage später stattfinden.
Das bedeutet: Inhalte, die nur per JavaScript vorhanden sind, können Tage verzögert indexiert werden. Bei einem neuen Blog-Artikel, der sofort sichtbar sein soll, ist das problematisch.
Einschränkungen des Google-Renderers
Der Googlebot-Renderer hat im Vergleich zu einem normalen Browser deutliche Limitierungen:
- Ältere Browser-API: Der Renderer basiert auf einer älteren Chrome-Version und unterstützt nicht alle modernen APIs
- Keine externe Authentifizierung: Inhalte hinter Login oder Paywall werden nicht gecrawlt
- Zeitlimit: Das Rendering stoppt nach einer bestimmten Zeit — tiefe JavaScript-Bäume werden möglicherweise nicht vollständig gerendert
- Crawl-Budget: JS-Rendering verbraucht mehr Ressourcen — bei großen Websites werden nicht alle Seiten gerendert
- Lazy Loading: Inhalte die erst beim Scrollen sichtbar werden, könnten nicht gecrawlt werden
Woran erkennst du ein JavaScript-SEO-Problem?
Es gibt mehrere Signale, dass deine SPA SEO-Probleme hat:
1. Quelltext vs. gerenderte Seite vergleichen
Öffne deine Website → Rechtsklick → "Seitenquelltext anzeigen". Wenn du dort keine Texte, Links oder Meta-Tags siehst, die im Browser sichtbar sind — hast du ein JavaScript-SEO-Problem.
2. Google Search Console
Unter "URL-Prüfung" kannst du sehen, wie Google deine Seite rendert. Klicke auf "Gerenderte Seite testen" — wenn das Rendering deutlich weniger Inhalt zeigt als dein Browser, liegt ein Problem vor.
3. Indexierungsprobleme
Wenn neue Inhalte nicht oder sehr spät in Google erscheinen, obwohl du sie in der Sitemap eingetragen hast, könnte Two-Wave Indexing die Ursache sein. Prüfe die Indexierung deiner Seiten regelmäßig.
4. JavaScript-SEO-Checker nutzen
Nutze unseren JavaScript-SEO-Checker: Füge deinen Quelltext ein und prüfe ob Title, H1, Description und Body-Text vorhanden sind.
Die vier Lösungsansätze
1. Server-Side Rendering (SSR)
Beim Server-Side Rendering wird das JavaScript auf dem Server ausgeführt und fertig gerendertes HTML an den Browser (und Googlebot) ausgeliefert. Googlebot sieht sofort alle Inhalte — kein Two-Wave Indexing.
Frameworks für SSR:
- Next.js (React) — mit
getServerSidePropsodergetStaticProps - Nuxt.js (Vue) — universelles Rendering per Standard
- SvelteKit (Svelte) — SSR per Standard
- Angular Universal (Angular) — SSR-Erweiterung
// Next.js Beispiel: SSR mit getServerSideProps
export async function getServerSideProps(context) {
const res = await fetch('https://api.beispiel.de/produkte')
const produkte = await res.json()
return {
props: { produkte }, // werden als Props an die Seite übergeben
}
}
export default function Produkte({ produkte }) {
return (
<main>
<h1>Unsere Produkte</h1>
{produkte.map(p => <div key={p.id}>{p.name}</div>)}
</main>
)
}
Vorteil SSR: Inhalte sofort für Google sichtbar, schnellere Indexierung.
Nachteil SSR: Höhere Server-Last, komplexere Infrastruktur, langsamere Response-Zeiten bei hohem Traffic.
2. Static Site Generation (SSG)
Bei Static Generation werden Seiten zum Build-Zeitpunkt als statisches HTML erzeugt. Das Ergebnis sind reine HTML-Dateien, die direkt ausgeliefert werden — kein Server-Rendering zur Laufzeit.
// Next.js Beispiel: SSG mit getStaticProps
export async function getStaticProps() {
const res = await fetch('https://api.beispiel.de/produkte')
const produkte = await res.json()
return {
props: { produkte },
revalidate: 3600, // Alle 60 Minuten neu generieren (ISR)
}
}
// getStaticPaths für dynamische Routen
export async function getStaticPaths() {
return {
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
fallback: 'blocking'
}
}
Vorteil SSG: Maximale Performance, perfektes Caching, ideal für Blog/Marketing-Seiten.
Nachteil SSG: Inhalte sind erst nach dem nächsten Build aktuell (außer bei ISR).
3. Incremental Static Regeneration (ISR)
ISR ist ein Mittelweg zwischen SSR und SSG. Seiten werden initial statisch generiert, aber nach einem definierten Intervall automatisch neu erzeugt. Bei Next.js reicht das revalidate-Parameter:
export async function getStaticProps() {
return {
props: { data: await fetchData() },
revalidate: 60, // Seite wird max. alle 60 Sekunden neu generiert
}
}
4. Dynamic Rendering (Prerendering für Bots)
Dynamic Rendering ist eine Übergangslösung: Normale Nutzer bekommen die JavaScript-App, Googlebot bekommt vorgerendertes HTML. Tools wie Prerender.io oder Rendertron übernehmen das Rendering.
# nginx Konfiguration für Dynamic Rendering
location / {
if ($http_user_agent ~* "googlebot|bingbot|yandex") {
proxy_pass http://prerender-service$request_uri;
break;
}
# Normale Nutzer bekommen die SPA
try_files $uri /index.html;
}
Wichtiger Hinweis: Google bezeichnet Dynamic Rendering als "temporäre Lösung" und empfiehlt langfristig SSR oder SSG. Es kann als Cloaking gewertet werden, wenn nicht sorgfältig implementiert.
Meta-Tags in SPAs korrekt setzen
Selbst wenn du SSR nutzt, muss du sicherstellen, dass Meta-Tags korrekt gesetzt werden. Bei React nutze react-helmet oder die native Next.js <Head>-Komponente:
// Next.js Head-Komponente
import Head from 'next/head'
export default function Produkt({ produkt }) {
return (
<>
<Head>
<title>{produkt.name} | Mein Shop</title>
<meta name="description" content={produkt.beschreibung.substring(0, 160)} />
<meta property="og:title" content={produkt.name} />
<meta property="og:image" content={produkt.bild_url} />
<link rel="canonical" href={`https://meinshop.de/produkte/${produkt.slug}`} />
</Head>
<main>
<h1>{produkt.name}</h1>
<p>{produkt.beschreibung}</p>
</main>
</>
)
}
Structured Data in JavaScript-Apps
Auch Structured Data (Schema Markup) muss im gerenderten HTML vorhanden sein. In Next.js kannst du JSON-LD direkt in die Head-Komponente einbinden:
const produktSchema = {
"@context": "https://schema.org",
"@type": "Product",
"name": produkt.name,
"description": produkt.beschreibung,
"image": produkt.bild_url,
"offers": {
"@type": "Offer",
"price": produkt.preis,
"priceCurrency": "EUR"
}
}
<Head>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(produktSchema) }}
/>
</Head>
Performance und Core Web Vitals bei SPAs
JavaScript-schwere Seiten haben oft schlechte Core Web Vitals. Das betrifft besonders:
- LCP (Largest Contentful Paint): Der Hauptinhalt erscheint erst, wenn JavaScript geladen und ausgeführt wurde
- CLS (Cumulative Layout Shift): Dynamisch nachgeladene Inhalte verschieben das Layout
- INP (Interaction to Next Paint): Schweres JavaScript blockiert den Main Thread
Mit SSR oder SSG verbesserst du diese Metriken deutlich, weil der Browser sofort mit dem Rendern des sichtbaren Inhalts beginnen kann.
Checkliste: JavaScript SEO richtig machen
- Quelltext prüfen: sind Title, H1, Meta-Description und Body-Text direkt im HTML?
- SSR oder SSG implementieren (Next.js, Nuxt.js, SvelteKit)
- Meta-Tags serverseitig rendern (react-helmet, Next.js Head)
- JSON-LD Structured Data im serverseitig gerenderten HTML einbinden
- Canonical-Tags korrekt setzen (speziell bei URL-Parametern in SPAs)
- Lazy Loading für nicht-kritische Bilder und Inhalte — aber nicht für SEO-relevante Hauptinhalte
- Sitemap aktuell halten mit allen URLs
- Google Search Console URL-Prüfung: "Live-Test" für kritische Seiten durchführen
- Crawl-Budget beachten: unnötige URLs mit robots.txt blockieren
Fazit: JavaScript und SEO müssen kein Widerspruch sein
JavaScript-Frameworks sind leistungsfähig und ermöglichen hervorragende User Experiences. Mit der richtigen Strategie — Server-Side Rendering oder Static Site Generation — können SPA-Websites genauso gut ranken wie traditionelle HTML-Seiten.
Der entscheidende Grundsatz: Alle kritischen SEO-Inhalte müssen im initialen HTML vorhanden sein — nicht erst nach JavaScript-Ausführung. Dazu gehören Title, Meta-Description, H1, Body-Text, strukturierte Daten und interne Links.
Prüfe jetzt mit unserem JavaScript-SEO-Checker, ob deine Website diesen Standard erfüllt. Füge den Quelltext ein und sieh sofort, welche SEO-Elemente fehlen.
Weitere technische SEO-Themen findest du in unserer Anleitung zu Hreflang-Tags für mehrsprachige Websites sowie im Artikel über Crawl-Budget-Optimierung.