seojuice

JavaScript SEO: Zo krijgt u een JS-app geïndexeerd

Vadim Kravcenko
Vadim Kravcenko
· Updated · 9 min read

TL;DR: Google kan JavaScript indexeren, maar client-side rendering voegt een extra (uitgestelde) stap toe tussen crawlen en indexeren. Plaats primaire content, route-specifieke metadata en crawlbare links in server-rendered of static HTML. Gebruik daarna de URL-inspectietool van Google Search Console om de gerenderde DOM, resources en eventuele JavaScript-fouten te verifiëren—niet om ervan uit te gaan dat je browser laat zien wat Google werkelijk ontvangen heeft.

Als je React-, Vue-, Angular- of zogenaamd server-rendered app ontbreekt in Google, stop dan met vragen of Googlebot “JavaScript ondersteunt.” Dat doet het. De relevante vraag is of Google de benodigde resources kan ophalen, de applicatie kan uitvoeren, de links kan ontdekken en een indexeerbare DOM kan opleveren voordat er ergens iets misgaat.

Renderingsmodel Wat de server verstuurt JavaScript SEO-risico Beste match
SSG Vooraf gebouwde HTML die tijdens de build wordt gegenereerd Laagste. Content is beschikbaar in de initiële response. Artikelen, documentatie, marketingpagina’s, directory’s en relatief stabiele publieke content.
SSR HTML die per request op de server wordt gegenereerd Laag. Crawlers kunnen primaire content lezen zonder JavaScript uit te voeren. Dynamische publieke pagina’s die verse of request-specifieke HTML nodig hebben.
CSR Een minimale HTML-shell plus JavaScript-bundels Hoogste. Content en links hangen af van het slagen van uitgestelde rendering. Geauthenticeerde dashboards en interactieve onderdelen die niet afhankelijk zijn van organische zoekresultaten.
Dynamic rendering Andere output voor bots en gebruikers Operationeel complex en niet langer aanbevolen door Google. Legacy-systemen die wachten op een architecturale oplossing, geen nieuwe implementaties.
Wat Googlebot ziet hangt af van waar je rendert: client-side is risicovol, server-rendered of static is veilig.

De pipeline waar je JavaScript-app doorheen moet overleven

Google Search Central beschrijft JavaScript-processing in drie afzonderlijke fases:

“Google verwerkt JavaScript-webapps in drie hoofd-fases: 1. Crawlen 2. Renderen 3. Indexeren”

Eerst vraagt Googlebot de URL op en parseert het de response. Als die response vooral een bijna lege applicatie-shell is, heeft Google je productkopie, artikeltekst, koppen, door de client gegenereerde metadata of route-links nog niet. Het heeft wel een URL, wat HTML-skeletwerk en verwijzingen naar resources.

Daarna zet Google voor rendering alleen in aanmerking komende pagina’s in een wachtrij. In de documentatie staat: “De pagina kan een paar seconden in deze wachtrij blijven, maar het kan ook langer duren.” Dat is het juiste model. Vermijd de oude claim dat JavaScript altijd een indexeringsvertraging van dagen of weken veroorzaakt; Google zegt dat niet. Er is wél een uitgestelde wachtrij, maar je pagina moet alsnog succesvol renderen zodra hij aan de voorkant van die wachtrij komt.

Die wachtrij is het stadium dat developers mentaal vaak overslaan. In je lokale browser lijkt de applicatie compleet, terwijl de opgehaalde response mogelijk maar weinig bevat: een root-element en bundle-verwijzingen (view-source is hier nuttig, maar het is slechts de helft van de diagnose).

Tijdens het renderen draait Google de pagina in een headless browser. Google bevestigt dat “Google Search JavaScript draait met een evergreen-versie van Chromium.” Moderne framework-syntax is daardoor meestal niet het probleem. Blokkades van resources, mislukte API-requests, runtime-excepties, content die pas na interactie verschijnt, en slechte link-markup zijn betere verdachten.

Na het renderen kan Google de resulterende DOM inspecteren en URLs extraheren die door JavaScript zijn toegevoegd. Die URLs gaan terug naar de crawl-wachtrij. Daarna volgt later indexering. Onze gidsen over wat crawlen betekent in SEO en hoe Google indexing werkt beschrijven de grenzen tussen deze fases.

Een client-gerenderde categoriepagina kan dus wel door Google als URL worden herkend, terwijl de producten, beschrijvingen en uitgaande links onbekend blijven. Ontdekking is niet hetzelfde als indexering. Een geïndexeerde URL is ook geen bewijs dat Google de volledige pagina daadwerkelijk heeft gezien.

Welke JavaScript rendering-strategie past bij welke taak: CSR voor privaat app-UI, SSR voor dynamische pagina’s, SSG voor stabiele content, ISR voor grote catalogi.

CSR werkt, maar is een kwetsbare default voor pagina’s die moeten ranken

Addy Osmani en Jason Miller definiëren client-side rendering op web.dev als: een applicatie renderen in de browser door JavaScript te gebruiken om de DOM aan te passen. Server-side rendering stuurt gegenereerde HTML vanaf de server. Static rendering maakt die HTML op build-tijd. Hydration voegt applicatiestatus en event handlers toe aan HTML die al bestaat.

Het SEO-probleem met CSR is structureel, niet ideologisch. Je belangrijkste content ontbreekt in de initiële response en hangt af van een ander systeem dat later nog meer werk afrondt. Dat kan prima werken. Toch zou ik niet elke publieke route hiervan afhankelijk maken, wanneer HTML al een complete klasse failure weghaalt.

“In brede zin moedigen we developers aan om server-side rendering of static rendering te overwegen in plaats van een volledige rehydration-aanpak.”

Dit is het advies van Osmani en Miller, geen instructie om elke applicatie om te bouwen naar een static site. Een privaat analytics-dashboard heeft andere eisen dan een publieke marktplaatscategorie. Render wat moet ranken op de server of tijdens build-tijd en voeg daarna client-side interactiviteit toe waar het zijn prijs waard is.

Frameworks bieden verschillende routes naar deze architectuur. Onze gids over SEO voor Next.js, React en Nuxt behandelt de framework-specifieke keuzes. Maar een framework met SSR-mogelijkheid garandeert geen server-rendered output. Ik ging ervan uit van wel, tot ik ontdekte dat de nuttige data pas na mount werd opgehaald (de framework-logo hielp me ook niet).

Geen dynamic rendering nieuw leven inblazen

Dynamic rendering geeft bots een vooraf gerenderde pagina, terwijl gebruikers de JavaScript-app ontvangen. Google documenteerde dit ooit als workaround, maar de huidige guidance is expliciet:

“Dynamic rendering was een workaround en geen langetermijnoplossing voor problemen met JavaScript-gegenereerde content in zoekmachines.”

Google’s documentatie over dynamic rendering adviseert in plaats daarvan server-side rendering, static rendering of hydration. Daar zou ik engineering-tijd in stoppen. Bot-detectie, aparte caches en twee mogelijke representaties van elke pagina maken het makkelijker voor content en metadata om uit elkaar te groeien.

Als dynamic rendering al een legacy-site ondersteunt, haal het dan niet zomaar weg zonder migratieplan. Accepteer het bestaan van een workaround, maar beschouw het niet als een solide basis voor een nieuwe architectuur.

De JavaScript SEO-fouten die ik als eerste zou checken

1. Primaire content is er pas nadat JavaScript is uitgevoerd

Haal de URL op zonder JavaScript uit te voeren. Als de response een applicatie-root bevat, een laaddbericht en verder weinig, dan hangt elk betekenisvol element af van Google’s rendering-fase. Verplaats de hoofdtekst, koppen, productrecords, artikelbody en essentiële navigatie naar SSR- of SSG-output.

Je hoeft JavaScript niet weg te halen. Je hebt een bruikbare HTML-basis nodig. Laat filters, calculators, accountstatus en interactieve controls waar passend bij de client. De scherpere test is: als de main bundle faalt, legt de response dan nog steeds uit wat deze URL bevat?

Test representatieve templates, niet één handige URL. Een homepage kan statisch zijn, terwijl categoriepagina’s pas volledig laden na mount. Productpagina’s kunnen SSR gebruiken, terwijl gefilterde routes de generieke shell teruggeven. Eén geslaagde pagina bewijst minder dan de meeste teams willen bewijzen.

Ik fix dit vóórdat ik metadata ga polijsten. Een server-rendered title kan geen lege artikelbody compenseren. Andersom geldt ook: een compleet artikel zit nog steeds in de problemen als Google een permanente loading state ontvangt. Eerst architectuur.

2. Je “links” zijn event handlers

Dit is één van de meest voorkomende problemen die we zien bij sites die met SEOJuice gekoppeld zijn. Een kaart of menu-item roept een router-methode aan, maar in de markup staat geen anchor of bestemming. Het gedraagt zich als navigatie voor een mens. Het is geen crawlbare link.

Google volgt echte anchors, geen click handlers:

<!-- Crawlable: een echte link die Google kan volgen -->
<a href="/products/blue-widget/">Blue Widget</a>

<!-- Onzichtbaar voor crawlen: helemaal geen link -->
<div onclick="navigate('/products/blue-widget/')">Blue Widget</div>
“Google kan je links alleen ontdekken als ze <a> HTML-elementen zijn met een href-attribuut.”

Deze formulering komt rechtstreeks uit Google Search Central. Voor navigeerbare bestemmingen horen echte anchors met een href. Je router kan de click nog steeds onderscheppen en client-side navigatie uitvoeren; progressive enhancement en SPA-gedrag zijn compatibel.

De schade stapelt zich op. Als een listing 100 klikbare cards toont als buttons of div-elementen, dan ontbreken er dus 100 bestemmingen in het link-discovery-mechanisme dat Google documenteert (een sitemap kan URLs blootleggen, maar herstelt hun interne-linkrelaties niet).

Bekijk menu’s, kaarten, pagination, breadcrumbs, modules met gerelateerde content, filters met stabiele bestemmingen en logo-navigatie. Als hele routegroepen ontbreken in Google, audit dan de links vanaf al bekende pagina’s voordat je indexing de schuld geeft. Onze gids met SEO best practices voor SPA’s gaat dieper in op route discovery en client-side navigatie.

3. robots.txt blokkeert JavaScript, CSS of API-resources

Google stelt dat Search geen JavaScript rendert uit geblokkeerde bestanden of op geblokkeerde pagina’s. Check brede robots.txt-regels voor asset-paden zoals /static/, /_next/, build-directories en geproxyte API-endpoints die nodig zijn om publieke content te bouwen.

Inspecteer de deployed asset-URL’s in plaats van blind te vertrouwen op repository-configuratie. Een CDN-regel, een robots-bestand dat alleen voor bepaalde omgevingen geldt, een authenticatiecheck of een verouderd deploypad kan ervoor zorgen dat productie anders werkt dan lokale ontwikkeling (productie blijft eigenwijs inventief).

Bevestig ook dat resources nuttige responses teruggeven aan Googlebot. Een bundle die 403 teruggeeft, een API-call die faalt zonder sessiecookie, of een verlopen chunk-URL kan de crawler achterlaten met een lege shell—ook al ziet robots.txt er schoon uit.

4. Belangrijke content vereist interactie

Content die alleen wordt opgehaald nadat iemand een tab selecteert, op “Load more” drukt, een scroll-afhankelijke request triggert of toestemming geeft, verschijnt mogelijk niet in de DOM die Google indexeert. In de troubleshooting-documentatie staat voor developers: “Verwacht dat Googlebot gebruikersverzoeken om toestemming weigert.”

Zorg dat indexeerbare content beschikbaar is zonder dat een gebruiker eerst een reis moet afleggen. Gesorteerde of gepagineerde content moet stabiele URL’s en crawlbare links hebben. Als een tab echt verschillende informatie bevat die de moeite waard is om te indexeren, zet die dan in de initiële HTML of geef het een crawlbare bestemming. Een crawler zou niet nodig moeten hebben om productgebruik te simuleren om je primaire copy te krijgen.

5. De router toont een 404 terwijl de server 200 teruggeeft

Een SPA kan een nette “Niet gevonden”-component tonen voor een ongeldige route, terwijl de server 200 OK rapporteert. Google behandelt dit als een soft-404-patroon. De gedocumenteerde fixes zijn: redirecten naar een URL waar de server een echte 404 teruggeeft, of de robots meta tag toevoegen of aanpassen naar noindex.

Ik heb liever dat je de juiste serverstatus gebruikt waar de stack dat toelaat. Statuscodes vertellen wat er gebeurde voordat de applicatie opstart. Ze zijn ook veel eenvoudiger te monitoren dan routerstate.

Check foutieve product-URL’s, verwijderde records, ongeldige pagination, verkeerde locale-routes en catch-all-paden. Dit soort edge cases nemen vaak dezelfde app shell over als geldige pagina’s en creëren stilletjes duizenden fout-URL’s die wel lijken te slagen.

6. Hydration beschadigt geldige server-HTML

SSR kan complete HTML teruggeven en toch falen nadat de pagina is geladen. web.dev merkt op dat server-rendered controls pas kunnen reageren zodra client-scripts zijn uitgevoerd en event handlers zijn gekoppeld. Een hydration-exceptie kan gebruikers achterlaten met dode controls; een mismatch kan content die in de response bestond vervangen of verwijderen.

Vergelijk drie states: raw HTML, de browser DOM na hydration en de door Google gerenderde DOM. Als de raw response klopt maar de gerenderde DOM content verliest, dan lost overstappen naar SSR niet het hele probleem op. Het heeft het probleem alleen verplaatst.

7. Titles, canonicals en descriptions komen te laat

Google bevestigt dat JavaScript de title en meta description kan instellen of wijzigen. Toch hoort route-specifieke metadata—waar praktisch—in de server- of static response. Als rendering faalt, kan Google de generieke applicatie-title tegenkomen in plaats van de pagina-specifieke versie.

Pas dezelfde discipline toe op canonical tags en robots-directives. Client-side wijzigingen kunnen worden verwerkt, maar kritieke indexing-signalen afhankelijk maken van execution levert weinig op en creëert een extra plek waar router-bugs door lekken naar templates.

Zo zie je wat Google echt gerenderd heeft

De URL-inspectietool in Google Search Console is de doorslaggevende check. Je browser, een lokale crawler en Lighthouse-runs kunnen gebreken blootleggen, maar geen van die tools representeert het resultaat dat Googlebot geregistreerd heeft.

  1. Inspecteer de exacte canonieke URL. Test niet alleen de homepage als de ontbrekende pagina’s een ander template of een andere data-fetching-route gebruiken.
  2. Open View Crawled Page. Gebruik voor een pagina die nog niet is geïndexeerd Test Live URL en inspecteer het resultaat van die test.
  3. Lees de gerenderde HTML. Zoek naar een herkenbare zin uit de primaire content, de route-specifieke title, canonieke URL en links naar diepere pagina’s.
  4. Check de screenshot. Lege roots, laadtoestanden, consent-overlays en ontbrekende secties kunnen een mislukte render snel zichtbaar maken.
  5. Bekijk consoleberichten en page resources. Let op exceptions, geblokkeerde bundles, mislukte API-calls en chunk-loading errors.
  6. Vergelijk met de raw response. Haal de URL op met een command-line HTTP-client. Het verschil tussen de response-HTML en de door Google gerenderde HTML is de JavaScript-afhankelijkheid die je moet evalueren.

Google’s JavaScript-troubleshootinggids zegt dat deze tools geladen resources, JavaScript console-output en exceptions, de gerenderde DOM en andere diagnostische informatie blootleggen. Als een belangrijke alinea of link ontbreekt in die DOM, dan is wachten op rankings geen teststrategie. Repareer het renderpad.

Bij SEOJuice zijn we met z’n tweeën—Lida en ik. Directe inspectie is belangrijk, omdat we ons niet kunnen veroorloven om elk indexing-issue om te zetten in een week speculatief debuggen. Raw HTML, gerenderde HTML, resources, console. Vier checks maken het probleem snel smaller.

We zagen het verschil heel duidelijk tijdens onze migratie van seojuice.io naar seojuice.com in januari 2026. Pagina’s zagen er correct uit in een normale browser, en live tests konden slagen, terwijl Google’s geregistreerde crawls voor sommige routes nog niet bijgebeend waren. Een geslaagde live test bewijst dat Google de pagina op testtijd kan renderen; het herschrijft geen historische crawls en garandeert geen indexering (ik wil ook graag dat knopje).

Een praktische release gate voor indexeerbare JavaScript-pagina’s

Behandel JavaScript SEO niet als een opruimklus na de launch. Voeg voor elke publieke template een kleine release gate toe:

  • De URL geeft de bedoelde statuscode terug zonder afhankelijk te zijn van client-side routing.
  • De raw HTML bevat de belangrijkste heading, primaire content en route-specifieke metadata.
  • Navigatie gebruikt anchor-elementen met href-attributen.
  • JavaScript, CSS en benodigde publieke dataresources zijn crawlbaar.
  • De pagina blijft bruikbaar als hydration faalt.
  • De gerenderde DOM bevat dezelfde primaire content en indexing-signalen als de response.
  • Ongeldige en verwijderde routes geven een echte error-response terug of een expliciete noindex-directive.

Dit is geen verzoek om pixel-perfecte HTML. De interactieve state mag verschillen. De eis is dat de betekenis van de pagina, de vindbare bestemmingen en de instructies voor indexering elke stap in Google’s pipeline overleven.

Waar SEOJuice past, en waar het niet past

SEOJuice werkt op een live site via een JavaScript-snippet of CMS-plugin. Het past continu on-page werk toe zoals interne links, meta titels en descriptions, schema markup en alt-tekst van afbeeldingen. Met de audit kun je ook ontbrekende metadata, dunne of ontbrekende gerenderde content, geblokkeerde resources, niet-crawlbare linkpatronen en indexatie-gaten blootleggen.

Het converteert geen CSR-applicatie naar SSR. Omdat het snippet client-side draait, deelt de output de rendering-afhankelijkheid die hierboven besproken is. Als primaire content ontbreekt in de HTML, los dan eerst het renderingsontwerp op; automatisering moet bovenop een pagina liggen die Google betrouwbaar kan verwerken.

Als de applicatie correct rendert en je de resterende on-page en indexatie-mistakes wilt identificeren, run dan de free SEO audit. Je kunt een gratis plan gebruiken zonder creditcard.

Veelgestelde vragen

Kan Google JavaScript indexeren?

Ja. Google Search voert JavaScript uit met een evergreen-versie van Chromium. JavaScript-pagina’s doorlopen nog steeds een uitgestelde rendering-fase, dus content kan vertraging oplopen of gemist worden als resources geblokkeerd zijn, uitvoering faalt of belangrijke informatie gebruikersinteractie vereist.

Waarom staat mijn React-, Vue- of Angular-app niet in Google?

De meest waarschijnlijke oorzaak is niet het framework zelf. Check of essentiële content en links pas verschijnen na client-side execution, of bundles of API’s niet beschikbaar zijn voor Googlebot, en of runtime errors rendering blokkeren. Inspecteer ook soft 404’s, generieke client-set metadata en navigatie zonder echte anchors.

Wat is het verschil tussen SSR, SSG en CSR voor SEO?

SSG genereert HTML op build-tijd. SSR genereert HTML op de server voor elke request. Beide maken primaire content zichtbaar in de response. CSR bouwt de pagina in de browser, waardoor die content afhankelijk wordt van Google’s latere rendering-stap. Voor publieke pagina’s die moeten ranken is SSG of SSR meestal het veiligere default.

Raadt Google dynamic rendering nog steeds aan?

Nee. Google noemt dynamic rendering een workaround in plaats van een langetermijnoplossing. De huidige guidance stuurt developers richting server-side rendering, static rendering of hydration. Start geen nieuwe implementatie rondom aparte output voor bots en gebruikers.

Tellen JavaScript-buttons en onClick-navigatie als links?

Niet als crawlbare links. Google documenteert linkdiscovery via anchor-elementen met href-attributen. Gebruik semantische anchors voor navigeerbare bestemmingen—ook als een client-side router ze onderschept om een volledige page reload te voorkomen.

Hoe zie ik de pagina die Googlebot gerenderd heeft?

Inspecteer de exacte URL in Google Search Console, open de gecrawlde of live-geteste pagina en bekijk de gerenderde HTML, screenshot, geladen resources en JavaScript-consoleberichten. Zoek in de HTML naar primaire copy en interne links. Als ze daar ontbreken, heeft Google tijdens die test niet de volledige pagina ontvangen.

Vertaal de inhoud terug in
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.