Single-page applications en SEO: complete gids voor SPA rendering in 2026

Vadim Kravcenko
Vadim Kravcenko
· 6 min read

TL;DR: SPA's zorgen standaard voor SEO-problemen. Google zet JavaScript-pagina's in een renderwachtrij — een proces dat uren tot dagen kan duren — en AI-crawlers (GPTBot, ClaudeBot, PerplexityBot) voeren helemaal geen JavaScript uit. De oplossing is server-side rendering via Next.js, Nuxt, Angular SSR of SvelteKit. In deze gids laat ik de exacte setup per framework zien, inclusief code, teststappen en het rendering-landschap van 2026.

SPA's hebben een SEO-probleem — en het is groter dan je denkt

Single-page applications laden één HTML-shell en vullen die daarna met JavaScript. Voor gebruikers voelt dat snel en app-achtig. Voor Googlebot eindigt het vaak als een lege <div id="app"></div>.

Client-side vs server-side JavaScript rendering comparison using the hamburger analogy
Client-side vs server-side rendering — choosing the right approach for SEO. Source: Lumar
Diagram showing how client-side JavaScript rendering works in single-page applications
How client-side JavaScript rendering works — and why it causes SEO problems. Source: Lumar

Ik heb via SEOJuice honderden SPA's geaudit. Het patroon is steeds hetzelfde: de site ziet er in de browser prima uit, JavaScript draait netjes, en zoekmachines zien amper iets. Of erger nog: ze zien de content pas dagen later, nadat die in Google's renderwachtrij heeft gestaan. Alleen al de Angular-hash-URL-bug heeft klanten meer organisch verkeer gekost dan welke algoritme-update ik me ook kan herinneren. Eén e-commerceklant gebruikte Angular met HashLocationStrategy en had 1.200 productpagina's. Google zag er precies één — de homepage. Alles na de # was onzichtbaar. Dat is geen kleine rankingdip. Dat is 60% van hun organische omzet die verdwijnt door een routingconfiguratie die, als je weet waar je moet kijken, in twee minuten te fixen is.

Zo ziet Google's renderproces er in de praktijk uit:

  1. Crawl — Googlebot haalt je URL op en krijgt de ruwe HTML-respons
  2. Queue — Als de pagina JavaScript nodig heeft, komt die in een renderwachtrij terecht
  3. Render — Google's Web Rendering Service (een headless Chromium-instance) voert JavaScript uit
  4. Index — De gerenderde HTML wordt geparseerd op content en links

Die wachtrij tussen stap 2 en stap 3? Die kan variëren van seconden tot dagen. Concurrenten met server-side gerenderde HTML slaan die wachtrij volledig over — hun content kan al bij de eerste crawl worden geïndexeerd.

En het wordt nog pijnlijker. In 2025 analyseerde Vercel meer dan een miljard crawler requests en ontdekte dat de meeste AI-crawlers helemaal geen JavaScript uitvoeren. GPTBot, ClaudeBot, PerplexityBot — ze verwerken ruwe, ongerenderde HTML. Een analyse van meer dan een half miljard GPTBot-fetches vond nul bewijs van JavaScript-executie. Als je SPA afhankelijk is van client-side rendering, dan is je content onzichtbaar voor de systemen die ChatGPT, Claude en Perplexity voeden.

"If your Next.js site ships critical pages as JavaScript-dependent SPAs, those pages are inaccessible to the systems shaping how people discover information."

— Vercel Engineering Blog (bron)

Die quote laat ik bewust in het Engels staan, omdat het een directe bronvermelding is. Vrij vertaald: als je kritieke pagina's als JavaScript-afhankelijke SPA's uitserveert, sluit je ze buiten van de systemen die bepalen hoe mensen informatie ontdekken.

Dit is geen nicheprobleem meer. Als je wilt dat je content in 2026 gevonden wordt door zowel Google als AI-zoekmachines, dan is server-side rendering niet langer een nice-to-have — het is een basisvoorwaarde.

CSR vs SSR vs SSG vs ISR — de keuze voor rendering

Er zijn vier manieren om een single-page application te renderen. Die keuze bepaalt of zoekmachines je content meteen, later of helemaal nooit zien.

AanpakHoe het werktSEO-impactTTFB (Time to First Byte)Beste voor
CSR (Client-Side Rendering)De browser downloadt een lege HTML-shell, daarna bouwt JavaScript de pagina opSlecht — Google zet de pagina in een renderwachtrij, AI-crawlers zien nietsSnel (maar leeg)Interne dashboards, adminpanelen, afgeschermde pagina's
SSR (Server-Side Rendering)De server genereert volledige HTML per request en stuurt een complete pagina terugUitstekend — volledige content bij de eerste crawlVariabel (afhankelijk van serververwerkingstijd)Dynamische content: e-commerce, nieuws, door gebruikers gegenereerde content
SSG (Static Site Generation)Pagina's worden tijdens het buildproces vooraf opgebouwd als statische HTMLUitstekend — snelste laadtijd, volledig crawlbaarHet snelst (geserveerd vanaf CDN)Blogs, documentatie, marketingpagina's, landingspagina's
ISR (Incremental Static Regeneration)Statische pagina's die volgens schema of on-demand opnieuw worden gegenereerdUitstekend — SSG-snelheid met verse contentSnel (gecachet met regeneratie op de achtergrond)Grote sites met content die periodiek verandert (productcatalogi, listings)

Belangrijkste conclusie

Elke pagina waarmee je in Google of AI-zoekmachines wilt ranken, moet server-side gerenderd of vooraf gerenderd zijn. CSR is prima voor afgeschermde pagina's en dashboards. Voor alles wat publiek toegankelijk is, gebruik je SSR, SSG of ISR.

De regel is simpel: als een URL vindbaar moet zijn in zoekmachines, dan moet die bij de eerste respons complete HTML teruggeven. Geen uitzonderingen. Geen "maar Google rendert tegenwoordig toch JavaScript". Google doet dat — soms, uiteindelijk, onbetrouwbaar — en AI-crawlers proberen het niet eens. Ik heb deze discussie met frontendontwikkelaars vaker gevoerd dan ik kan tellen. Het gesprek stopt meestal zodra ik hun site in Google's URL Inspection tool laat zien en ze een lege pagina zien waar hun prachtige UI had moeten staan.

React en Next.js

Gewone React (Create React App, Vite met React) is alleen CSR. Google kan daar slecht mee overweg. Next.js is het antwoord — en sinds de App Router de standaard werd in Next.js 13+, is het SEO-verhaal daar een stuk beter geworden.

React Server Components — de standaard in 2026

Met de App Router renderen componenten standaard op de server. Je voegt alleen 'use client' toe wanneer een component browser API's of interactiviteit nodig heeft. Dat betekent dat het grootste deel van je pagina-inhoud als pure HTML wordt geleverd — zonder dat JavaScript eerst nog iets hoeft op te bouwen.

// app/blog/[slug]/page.tsx — Server Component (default)
import { Metadata } from 'next'

// Dynamic metadata for each blog post
export async function generateMetadata({ params }): Promise<Metadata> {
  const post = await getPost(params.slug)
  return {
    title: post.title,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
      publishedTime: post.publishedAt,
    },
    alternates: {
      canonical: `https://example.com/blog/${params.slug}`,
    },
  }
}

// This component runs on the server — zero JS shipped to the browser
export default async function BlogPost({ params }) {
  const post = await getPost(params.slug)

  return (
    <article>
      <h1>{post.title}</h1>
      <div>{post.content}</div>
    </article>
  )
}

Statische generatie met generateStaticParams

Voor content die niet vaak verandert (blogposts, landingspagina's), genereer je pagina's vooraf tijdens het buildproces:

// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await getAllPosts()
  return posts.map((post) => ({ slug: post.slug }))
}

// Combined with the page component above,
// Next.js generates static HTML at build time for every post

ISR voor grote catalogi

Voor e-commerce sites met duizenden producten gebruik je ISR om pagina's volgens schema opnieuw te valideren:

// app/products/[id]/page.tsx
export const revalidate = 3600 // Regenerate every hour

export default async function ProductPage({ params }) {
  const product = await getProduct(params.id)
  return <ProductDetail product={product} />
}

Als je vastzit aan gewone React en niet naar Next.js kunt migreren, gebruik dan tijdelijk een pre-rendering service zoals Prerender.io. Maar laten we eerlijk zijn: dat is duct tape, geen oplossing. Elke maand dat je de migratie uitstelt, is een maand met suboptimale indexatie.

Vue en Nuxt 3

Hetzelfde verhaal, ander ecosysteem. Gewone Vue met Vue Router is alleen CSR. Nuxt 3 geeft je SSR, SSG, ISR en edge rendering met Nitro — allemaal binnen één framework.

Universal rendering (standaard SSR)

Nuxt 3 gebruikt universal rendering standaard. Geen extra configuratie nodig — je pagina's worden server-side gerenderd bij de eerste laadbeurt en daarna gehydrateerd voor client-side navigatie.

<!-- pages/blog/[slug].vue -->
<script setup>
const route = useRoute()
const { data: post } = await useFetch(`/api/posts/${route.params.slug}`)

// Per-page SEO metadata
useHead({
  title: post.value.title,
  meta: [
    { name: 'description', content: post.value.excerpt },
    { property: 'og:title', content: post.value.title },
    { property: 'og:description', content: post.value.excerpt },
  ],
  link: [
    { rel: 'canonical', href: `https://example.com/blog/${route.params.slug}` }
  ]
})
</script>

<template>
  <article>
    <h1>{{ post.title }}</h1>
    <div v-html="post.content" />
  </article>
</template>

Hybride rendering — verschillende strategieën per route

Met routeRules in Nuxt 3 kun je rendering-strategieën combineren binnen dezelfde app. Dat is handig voor sites met zowel statische marketingpagina's als dynamische content:

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/':          { prerender: true },           // SSG — homepage
    '/blog/**':   { isr: 3600 },                 // ISR — blog posts regenerate hourly
    '/products/**': { ssr: true },               // SSR — dynamic product pages
    '/dashboard/**': { ssr: false },             // CSR — authenticated dashboard
  }
})

Edge rendering met Nitro

Nitro, de server engine van Nuxt 3, ondersteunt deployment naar edge-platformen (Cloudflare Workers, Vercel Edge, Netlify Edge). Dat betekent dat je SSR-pagina's renderen op CDN edge-locaties die het dichtst bij de gebruiker zitten — sub-50ms TTFB is realistisch. Voor SEO betekent dat snellere laadtijden, betere Core Web Vitals en vaak ook efficiënter crawlen door Google.

Angular SSR

Angular was historisch gezien het lastigste framework om SEO-vriendelijk te maken. Dat is flink veranderd sinds Angular 17, dat SSR een volwaardige standaardoptie maakte met ingebouwde hydration support. Geen geknutsel meer met Angular Universal als iets dat je er achteraf nog aan vastplakt.

SSR instellen in Angular 17+

Nieuwe projecten krijgen standaard SSR wanneer je de CLI gebruikt:

# New project with SSR enabled
ng new my-app --ssr

# Add SSR to an existing project
ng add @angular/ssr

Dynamische meta tags met Angular-services

// product-page.component.ts
import { Component, OnInit } from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-product-page',
  template: `
    <article>
      <h1>{{ product.name }}</h1>
      <p>{{ product.description }}</p>
    </article>
  `
})
export class ProductPageComponent implements OnInit {
  product: any;

  constructor(
    private meta: Meta,
    private title: Title,
    private route: ActivatedRoute,
    private productService: ProductService
  ) {}

  ngOnInit() {
    const id = this.route.snapshot.paramMap.get('id');
    this.productService.getProduct(id).subscribe(product => {
      this.product = product;
      this.title.setTitle(product.name);
      this.meta.updateTag({ name: 'description', content: product.description });
      this.meta.updateTag({ property: 'og:title', content: product.name });
    });
  }
}

Incremental Hydration (Angular 19+)

Angular 19.2 introduceerde incremental hydration, voortbouwend op de @defer API. Componenten renderen volledige HTML op de server, maar hydrateren pas op de client wanneer dat wordt getriggerd (in viewport, bij interactie, enzovoort). Dat vermindert de hoeveelheid JavaScript die naar de browser wordt gestuurd, terwijl volledige SSR-content beschikbaar blijft voor crawlers.

Angular-specifieke valkuil

Hash-based routing (HashLocationStrategy) produceert URL's zoals example.com/#/products. Google negeert alles na de #. Je productcatalogus van 500 pagina's lijkt daardoor op één pagina. Stap direct over op PathLocationStrategy — dat is de standaard in Angular, maar sommige legacy-projecten gebruiken nog steeds hash routing. Dit is exact de bug die de e-commerceklant die ik hierboven noemde 60% van hun organische verkeer kostte. Ze gebruikten al twee jaar hash routing. Twee jaar aan productpagina's waarvan Google niet eens wist dat ze bestonden. De oplossing duurde 20 minuten. Het herstel duurde vier maanden.

SvelteKit

SvelteKit is stilletjes een van de beste frameworks voor SEO-by-default geworden. SSR staat standaard aan — je moet er actief voor kiezen om het uit te zetten. Het framework compileert zichzelf grotendeels weg, waardoor er veel minder JavaScript wordt verstuurd dan bij React of Angular.

Standaard SSR — geen configuratie nodig

Elke SvelteKit-pagina wordt standaard server-side gerenderd. Je +page.svelte-bestanden genereren complete HTML bij het eerste request:

<!-- src/routes/blog/[slug]/+page.svelte -->
<script>
  export let data;
</script>

<svelte:head>
  <title>{data.post.title}</title>
  <meta name="description" content={data.post.excerpt} />
  <link rel="canonical" href={`https://example.com/blog/${data.post.slug}`} />
</svelte:head>

<article>
  <h1>{data.post.title}</h1>
  {@html data.post.content}
</article>
// src/routes/blog/[slug]/+page.server.ts
export async function load({ params }) {
  const post = await getPost(params.slug);
  return { post };
}

Hybride rendering per route

Net als Nuxt laat SvelteKit je rendering per route aansturen:

// src/routes/blog/[slug]/+page.ts
export const prerender = true;  // SSG — generate at build time

// src/routes/dashboard/+page.ts
export const ssr = false;       // CSR-only for authenticated content

Waarom SvelteKit aandacht verdient voor SEO: de compiler elimineert de framework-runtime. Een SvelteKit-pagina verstuurt een fractie van de JavaScript van een vergelijkbare Next.js- of Nuxt-pagina. Minder JavaScript betekent snellere LCP, betere INP-scores en blijere Core Web Vitals — allemaal rankingsignalen.

De SPA SEO-checklist

Elke SPA moet deze checks doorstaan. Gesorteerd op impact — pak eerst de bovenste punten aan.

#CheckWaarom het belangrijk isHoe je het oplost
1SSR of SSG ingeschakeld voor alle publieke pagina'sZonder dit zet Google je pagina's in een renderwachtrij en zien AI-crawlers nietsNext.js App Router, Nuxt 3, Angular SSR of SvelteKit
2Schone URL's (geen hash fragments)Hash-URL's (#/page) zijn onzichtbaar voor zoekmachinesGebruik history-based routing — de standaard in alle moderne frameworks
3Unieke title tag per paginaDezelfde title op elke route betekent dat Google er één kiest en de rest negeertgenerateMetadata (Next.js), useHead() (Nuxt), Meta service (Angular), <svelte:head>
4Unieke meta description per paginaBepaalt je snippet in de zoekresultatenDezelfde libraries als voor title tags — stel dit per route in
5Canonical tags op elke paginaVoorkomt duplicate content-problemen door query params en trailing slashesVoeg <link rel="canonical"> per pagina toe in je metadata
6Juiste heading-hiërarchie (H1 > H2 > H3)Geeft contentstructuur door aan crawlersEén H1 per pagina, logische nesting in componenten
7Interne links gebruiken echte <a href>-tagsAlleen-JavaScript-navigatie (onClick-handlers) blokkeert crawlersGebruik framework Link-components: <Link>, <NuxtLink>, routerLink
8XML sitemap ingediendHelpt Google pagina's te ontdekken die niet via links bereikbaar zijnGenereer met next-sitemap, nuxt-simple-sitemap of framework-specifieke tooling
9Code splitting en lazy loadingVerkleint de initiële JS-bundle, verbetert LCP en INPDynamic imports (next/dynamic, defineAsyncComponent, @defer)
10Schema markup (JSON-LD) op belangrijke pagina'sMaakt rich snippets mogelijk en helpt AI-crawlers content te begrijpenJSON-LD in <head> of <body> — server-side gerenderd, niet via JS geïnjecteerd

Veelgemaakte SPA SEO-fouten

Dit zijn de fouten die ik in bijna elke SPA-audit zie. Echt stuk voor stuk rankingslopers.

Fout 1: vertrouwen op CSR voor publieke pagina's

"Maar Google rendert JavaScript toch!" — ja, soms, uiteindelijk, als je JS geen error gooit, als de renderwachtrij niet vastloopt, als je JavaScript niet in een timeout eindigt, en als geen van je third-party scripts de render verstoort. Dat zijn nogal wat mitsen en maren om je organische verkeer op te gokken. En AI-crawlers proberen het niet eens.

// WRONG — CSR-only React app
// Google sees: <div id="root"></div>
import { createRoot } from 'react-dom/client';
const root = createRoot(document.getElementById('root'));
root.render(<App />);

// RIGHT — Next.js Server Component
// Google sees: fully rendered HTML with all content
export default async function Page() {
  const data = await fetchData();
  return <Article data={data} />;
}

Fout 2: hash-based routing

Angular HashLocationStrategy en de hash mode van Vue Router produceren URL's zoals example.com/#/products/shoes. Google negeert alles na de #. Daardoor lijkt je hele applicatie op één pagina.

// WRONG — Vue Router hash mode
const router = createRouter({
  history: createWebHashHistory(),  // URLs: example.com/#/about
  routes
})

// RIGHT — Vue Router history mode
const router = createRouter({
  history: createWebHistory(),      // URLs: example.com/about
  routes
})

Fout 3: dezelfde title tag op elke pagina

SPA's worden geleverd met één <title> in de HTML-shell. Als je die niet dynamisch per route bijwerkt, heeft elke pagina dezelfde title. Google indexeert dan één versie en negeert de rest.

<!-- WRONG — static HTML shell with one title -->
<!DOCTYPE html>
<html>
  <head>
    <title>My App</title>  <!-- Same for every route -->
  </head>
  <body><div id="app"></div></body>
</html>

<!-- RIGHT — dynamic metadata per route (Nuxt example) -->
<script setup>
useHead({
  title: `${product.name} | MyStore`,
  meta: [{ name: 'description', content: product.summary }]
})
</script>

Fout 4: JavaScript-errors blokkeren rendering

Eén enkele uncaught error in je applicatie kan voorkomen dat de hele pagina rendert. Google's Web Rendering Service probeert het niet opnieuw. De pagina blijft leeg in de index.

Ik zie dit constant: een third-party analytics script gooit een error, of een ontbrekende API-respons laat de component tree crashen. Het resultaat? Google indexeert een lege pagina. Eén klant had een Hotjar snippet die af en toe faalde in Google's renderer. Hun productpagina's verschenen daardoor willekeurig leeg in de URL Inspection tool van GSC. De oplossing was een error boundary rond de analytics-initialisatie. Duurde 10 minuten. Had maandenlang stilletjes hun indexatie geschaad.

Oplossing: voeg error boundaries toe in React (ErrorBoundary-componenten), gebruik NuxtErrorBoundary in Nuxt, en test altijd met JavaScript uitgeschakeld (daarover zo meer).

Fout 5: geen sitemap

SPA's met client-side routing tonen hun URL-structuur niet via HTML-links zoals multi-page sites dat doen. Zonder sitemap ontdekt Google pagina's alleen via crawlbare links — en als je interne linking JavaScript-gedreven is, vindt het misschien helemaal niets.

# Install next-sitemap for Next.js
npm install next-sitemap

# next-sitemap.config.js
module.exports = {
  siteUrl: 'https://example.com',
  generateRobotsTxt: true,
  changefreq: 'weekly',
  // Exclude routes that shouldn't be indexed
  exclude: ['/dashboard/*', '/api/*', '/admin/*'],
}

Fout 6: JavaScript blokkeren in robots.txt

Als je robots.txt CSS- of JS-bestanden blokkeert, kan Google's renderer je pagina niet opbouwen. We zien dit verrassend vaak — meestal als overblijfsel van een oude standaardconfiguratie.

# WRONG — blocking JS and CSS
User-agent: *
Disallow: /static/js/
Disallow: /static/css/

# RIGHT — allow all resources needed for rendering
User-agent: *
Disallow: /api/
Disallow: /dashboard/
Allow: /static/

Hoe je de SEO van je SPA test — stap voor stap

Google Lighthouse-auditrapport met scores voor Performance, Accessibility, Best Practices en SEO
Een Lighthouse-auditrapport. JavaScript-zware SPA's scoren vaak lager op performance-metrics door de overhead van client-side rendering. Bron: Shopify

Ga er niet vanuit dat je SPA crawlbaar is alleen omdat hij werkt in Chrome. Zo controleer je wat zoekmachines daadwerkelijk zien.

Test 1: Google Search Console URL Inspection

De URL Inspection Tool is je beste diagnose-instrument. Voer een willekeurige URL in en klik op "Test Live URL". Google haalt je pagina op, rendert die met zijn Web Rendering Service en laat je het resultaat zien.

Waar je op moet letten:

  • Screenshot-tab — Zie je je echte content, of een lege pagina / loading spinner?
  • Rendered HTML-tab — Staat je content in de DOM? Zoek op belangrijke tekststrings.
  • More Info-tab — Controleer op JavaScript console errors. Elke uncaught error kan betekenen dat rendering is mislukt.
  • Page resources — Controleer of geen kritieke JS/CSS-bestanden geblokkeerd zijn of errors teruggeven.

Test 2: bekijk de ruwe HTML met View Source

Open je pagina, klik met rechts en kies View Page Source. Niet Elements in DevTools — echt de broncode. Als je hoofdcontent daar niet in staat, dan vertrouw je op client-side rendering. Dat is meteen een alarmsignaal voor SEO.

Een simpele vuistregel: als je in de broncode alleen een root-element, scripts en weinig inhoud ziet, dan zien AI-crawlers waarschijnlijk exact hetzelfde kale skelet.

Test 3: schakel JavaScript uit

Zet JavaScript tijdelijk uit in Chrome DevTools of gebruik een extensie die JS blokkeert. Herlaad daarna de pagina. Zie je nog steeds de belangrijkste content, headings, interne links en productinformatie? Mooi. Zie je alleen een lege shell, spinner of foutmelding? Dan heb je een CSR-probleem, geen theoretisch SEO-debat.

Dit is trouwens een van mijn favoriete reality checks in audits. Iedereen voelt zich heel zeker over hun moderne frontendstack tot de pagina zonder JavaScript ineens verandert in een digitaal braakland.

Test 4: voer een volledige SEO-audit uit

Onze gratis SEO-audittool scant je SPA op renderingproblemen, ontbrekende meta tags, kapotte links en toegankelijkheidsproblemen. Je ziet exact wat zoekmachines zien — geen login nodig, resultaat in 30 seconden.

Test 5: controleer toegang voor AI-crawlers

Omdat AI-crawlers geen JavaScript renderen, moet je controleren of ze je content überhaupt kunnen bereiken met de AI Crawler Inspector. Die simuleert hoe GPTBot, ClaudeBot en andere AI-bots je pagina's zien.

Wat is er in 2026 veranderd?

Het SEO-landschap voor SPA's ziet er in 2026 wezenlijk anders uit dan zelfs twee jaar geleden. Dit is wat nu telt.

React Server Components zijn de nieuwe standaard

Met de Next.js App Router renderen componenten standaard op de server. Je kiest expliciet voor client-side rendering met 'use client'. Dat draait het oude model om — in plaats van dat alles CSR is met SSR er later opgeplakt, is alles SSR met CSR alleen waar nodig. De SEO-gevolgen zijn groot: het grootste deel van je applicatie wordt automatisch als pure HTML geleverd.

Edge rendering is production-ready

Nuxt 3 met Nitro, Next.js Edge Runtime en SvelteKit adapters deployen SSR nu naar CDN edge-locaties (Cloudflare Workers, Vercel Edge Functions). Je pagina's renderen op de edge node die het dichtst bij de gebruiker zit — of de crawler. Sub-50ms TTFB is wereldwijd haalbaar.

Angular heeft eindelijk first-class SSR

Angular 17+ bouwde SSR in de CLI met ng new --ssr. Angular 19 voegde incremental hydration toe. De tijd van pijnlijke Angular Universal-setups is voorbij. Als je nog steeds een Angular-app draait die alleen CSR gebruikt, is het migratiepad nu opvallend rechttoe rechtaan.

AI-crawlers zijn een echt SEO-kanaal

GPTBot, ClaudeBot, PerplexityBot en anderen crawlen het web om trainingsdata op te bouwen en AI-search aan te sturen. Geen van hen voert JavaScript uit. Analyse van meer dan een half miljard GPTBot-requests vond nul bewijs van JS-executie. Als je wilt dat je content wordt geciteerd in AI-gegenereerde antwoorden, is SSR de enige serieuze optie.

"Seeing rendered HTML, not just source code, is important in diagnosing if there's an indexing problem. Google can only discover your links if they are <a> HTML elements with an href attribute."

— Martin Splitt, Developer Advocate bij Google (bron)

Ook deze quote laat ik als directe bron in het Engels staan. De kern is simpel: Google kan je links alleen betrouwbaar ontdekken als het echte <a>-elementen met een href zijn, en gerenderde HTML is cruciaal om indexatieproblemen te diagnosticeren.

Core Web Vitals blijven belangrijk

LCP, INP en CLS blijven rankingsignalen. SPA's die grote JavaScript-bundles versturen, krijgen het moeilijk op LCP (de pagina doet te lang over het tonen van betekenisvolle content) en INP (interacties voelen traag aan). Code splitting, lazy loading en minimale client-side JavaScript zijn niet optioneel — het zijn performance-eisen die direct invloed hebben op rankings.

"Prerendering your site statically or on the server is the best practice for SEO — it makes crawlers willing to reindex your site more frequently."

— Vercel Engineering Blog (bron)

Snelle framework-vergelijking

Twijfel je welk framework je moet kiezen? Zo vergelijken ze zich specifiek op SEO.

FeatureNext.js (React)Nuxt 3 (Vue)Angular SSRSvelteKit
Standaard SSRJa (App Router)JaJa (sinds v17)Ja
Statische generatiegenerateStaticParamsprerender: trueng build --prerenderexport const prerender = true
ISR-ondersteuningIngebouwd (revalidate)Ingebouwd (isr: seconds)Handmatig via service workerVia adapter-specifieke config
Edge renderingVercel Edge, CloudflareNitro (multi-platform)BeperktMeerdere adapters
Metadata API per paginagenerateMetadatauseHead()Meta + Title services<svelte:head>
Verstuurde client JSGemiddeld (RSC helpt)GemiddeldZwaarMinimaal (weggecompileerd)
Community/ecosysteemGrootstSterkEnterprise-gerichtGroeit snel

Veelgestelde vragen

Kan Google single-page applications crawlen?

Ja, maar met kanttekeningen. Google's Web Rendering Service gebruikt een headless Chromium-browser om JavaScript uit te voeren en SPA's te renderen. Die rendering gebeurt echter in een aparte wachtrij na de eerste crawl, wat indexatie uren tot dagen kan vertragen. Pagina's met JavaScript-errors renderen mogelijk nooit. Voor betrouwbare indexatie gebruik je SSR of SSG — vertrouw niet op Google's renderwachtrij voor tijdgevoelige content.

Is een single-page application slecht voor SEO?

Een SPA die alleen CSR gebruikt is slecht voor SEO. Een SPA met server-side rendering niet. Het framework maakt niet uit — wat telt is of de eerste HTML-respons je content bevat. Next.js, Nuxt, Angular SSR en SvelteKit produceren allemaal volledig crawlbare SPA's. Het "SPA vs. SEO"-probleem is jaren geleden al opgelost; het echte probleem zijn developers die die oplossing niet implementeren.

Heb ik server-side rendering nodig voor een React-app?

Voor elke pagina die vindbaar moet zijn in zoekmachines? Ja. React op zichzelf (via Vite of Create React App) is alleen CSR — zoekmachines zien een lege pagina. Next.js voegt SSR, SSG en ISR toe. Met React Server Components in de App Router renderen de meeste componenten standaard op de server. Als je React-app publieke content serveert, is Next.js de standaardoplossing.

Hoe gaan AI-zoekmachines om met SPA's?

Dat doen ze niet. GPTBot (OpenAI), ClaudeBot (Anthropic), PerplexityBot en andere AI-crawlers voeren geen JavaScript uit. Ze parsen alleen ruwe HTML. Analyse van meer dan een half miljard GPTBot-requests vond nul bewijs van JavaScript-rendering. Als je content client-side gerenderd is, is die onzichtbaar voor AI-zoekmachines. SSR is de enige manier om te verschijnen in AI-gegenereerde antwoorden en citaties.

Wat is het verschil tussen SSR, SSG en ISR?

SSR (Server-Side Rendering) genereert HTML bij elk request — het beste voor dynamische content. SSG (Static Site Generation) genereert HTML tijdens het buildproces — het snelst, maar vereist nieuwe builds bij contentwijzigingen. ISR (Incremental Static Regeneration) genereert statische pagina's die automatisch volgens schema opnieuw worden opgebouwd — het combineert de snelheid van SSG met verse content. Alle drie leveren volledige HTML aan zoekmachines bij het eerste request. Kies op basis van hoe vaak je content verandert.

Conclusie

SPA's zijn niet per definitie slecht voor SEO. Maar SPA's die alleen CSR gebruiken wel — en in 2026 zijn ze ook onzichtbaar voor AI-zoekmachines.

De oplossing bestaat al jaren. Next.js, Nuxt 3, Angular SSR en SvelteKit leveren allemaal server-side gerenderde HTML. React Server Components hebben dat nog beter gemaakt — het grootste deel van je app rendert automatisch op de server. Er is geen excuus meer om een publiek toegankelijke SPA zonder server-side rendering te publiceren.

Weet je niet zeker of je SPA crawlbaar is, voer dan een gratis audit uit — het kost 30 seconden en laat exact zien wat Google ziet. Voor zichtbaarheid bij AI-crawlers kun je de AI Crawler Inspector gebruiken.

Gerelateerde artikelen:

SEOJuice
Stay visible everywhere
Get discovered across Google and AI platforms with research-based optimizations.
Works with any CMS
Automated Internal Links
On-Page SEO Optimizations
Get Started Free

no credit card required

More articles

No related articles found.