Ik maak van de tekst van elke pagina een embedding, een reeks getallen die de betekenis van de tekst vastlegt, en groepeer pagina’s die elkaars dichtstbijzijnde buren zijn. Per groep tel ik de links in de tekst, en ik leg de vertoningen uit Search Console ernaast, het aantal keer dat een pagina in de zoekresultaten stond. Daarna kijk ik naar groepen zonder pagina die de andere verbindt, pagina’s die bij elkaar horen maar niet naar elkaar linken, korte pagina’s met relatief veel vertoningen en onderwerpen van mijn lijst zonder eigen groep.
Een crawl is het ophalen van alle pagina’s van je site met een programma als Screaming Frog. Die lijst URL’s zegt nog niet welke pagina’s over hetzelfde onderwerp gaan, en daarmee ook niet welk onderwerp ontbreekt.
Een embedding, ook wel vector, is een reeks getallen die een AI-model van een tekst maakt. Teksten met dezelfde betekenis krijgen embeddings die dicht bij elkaar liggen, ook als ze andere woorden gebruiken. Google beschrijft neural matching als een AI-systeem dat de begrippen in zoekopdrachten en pagina’s begrijpt en aan elkaar koppelt.1
In dit stuk groepeer ik de pagina’s van een kleine zakelijke site die ik meet op hun embeddings. Daarna leg ik de interne links ernaast, de links van de ene pagina van je site naar een andere, en de vertoningen (impressions), het aantal keer dat een pagina in de zoekresultaten stond. Het script dat de groepen en de links telt, staat onderaan en kun je zelf draaien.
Wat je nodig hebt
- Een crawl. Screaming Frog of een andere crawler, met per pagina het aantal woorden (de kolom Word Count) en de export All Inlinks voor de links.
- Embeddings van je pagina’s. Die maak je met een embeddingmodel van een AI-aanbieder, via je eigen account en de koppeling (API) van die aanbieder. Elke aanroep kost geld bij die aanbieder, dus kijk het tarief na voordat je begint. Mijn systeem gebruikt text-embedding-004 van Google op de eerste 8.000 tekens van de tekst van een pagina, en dat geeft 768 getallen per pagina.2
- Python 3 met numpy, voor het script. Numpy installeer je met
pip install numpy. - Google Search Console, voor de vertoningen per pagina.
- Tijd. Het script deed de 23 pagina’s van die site in minder dan een seconde. De crawl en het maken van de embeddings komen daar bovenop.
Het script begint bij een CSV met de embeddings. Code om het model aan te roepen staat niet in dit stuk, omdat die per aanbieder verschilt.
Werk je met Screaming Frog, dan kan die sinds versie 22 zelf embeddings laten maken via een AI-aanbieder. Volgens Screaming Frog gaat dat verder dan de vergelijking van tekst die het programma voor dubbele inhoud doet.3 Het programma markeert daarmee ook pagina’s die weinig samenhangen met het onderwerp van de rest van de site.4 De groepen en de links per groep uit dit stuk maak je met het script.
1. Kies de pagina’s met genoeg tekst
Neem alleen HTML-pagina’s met status 200 en eigen tekst. Laat pdf’s, doorverwijzingen (redirects) en pagina’s met bijna alleen een formulier weg. De embedding van een pagina met weinig tekst zegt weinig over een onderwerp.
- Open in Screaming Frog het tabblad Internal en filter op HTML.
- Houd de pagina’s met statuscode 200 die indexeerbaar zijn, dus pagina’s die Google mag opnemen.
- Exporteer de lijst met de kolommen Address en Word Count.
Het script slaat pagina’s met minder dan 500 tekens tekst over. Het gaat dan om de tekst die je naar het model stuurde, die je in stap 2 als kolom tekens meegeeft; Word Count telt woorden en is iets anders. Op de voorbeeldsite hadden 3 van de 26 pagina’s met een embedding minder tekst, waaronder het contactformulier, en bleven er 23 over.2
Controle. Elke pagina op je lijst heeft status 200 en een eigen tekst van meer dan een paar zinnen.
2. Maak van elke pagina een embedding
Stuur de hoofdtekst van elke pagina, zonder menu en voettekst, naar het embeddingmodel en bewaar per pagina de URL en de getallen. Gebruik voor alle pagina’s hetzelfde model, want embeddings van verschillende modellen kun je niet met elkaar vergelijken.
Zet de uitkomst in een CSV met per pagina één regel:
url, het adres van de pagina;vector, de getallen van de embedding, gescheiden door spaties of komma’s;woorden, het aantal woorden uit de crawl (mag leeg);tekens, het aantal tekens van de tekst die je naar het model stuurde (mag leeg).
Controle. Elke regel heeft evenveel getallen. Het script stopt als de regels niet even lang zijn. Dat vangt een tweede model alleen op als dat een ander aantal getallen geeft, dus houd zelf bij welk model je gebruikte.
3. Bereken hoe dicht de pagina’s bij elkaar liggen
De cosinusovereenkomst (cosine similarity) is een maat voor hoe dicht twee embeddings bij elkaar liggen, van -1 tot 1. Hoe dichter bij 1, hoe meer de teksten op elkaar lijken. Het script rekent hem uit voor elk paar pagina’s.
Op de voorbeeldsite lag de overeenkomst over de 253 paren tussen 0,67 en 0,97, met 0,84 als gemiddelde.5 Ook het minst gelijke paar lag nog op 0,67. Dat past bij een site waar alle pagina’s over hetzelfde vak gaan.
Een vaste grens, zoals “boven 0,9 hoort bij elkaar”, valt op zo’n site anders uit dan op een site met uiteenlopende onderwerpen. Daarom groepeer ik op de buren van elke pagina en niet op een vast getal.
0,84
gemiddelde cosinusovereenkomst tussen de embeddings van twee pagina's van een kleine zakelijke site, over 253 paren, met 0,67 als laagste en 0,97 als hoogste
Eigen meting RankFellow · 23 pagina's · september tot oktober 2026
Controle. Het script toont het gemiddelde, de laagste en de hoogste overeenkomst. Zo zie je hoe ver de pagina’s van je site uit elkaar liggen, voordat je de groepen leest.
4. Groepeer pagina’s die elkaars dichtstbijzijnde buren zijn
De regel in het script heeft drie delen.
- Zoek voor elke pagina de twee pagina’s met de hoogste overeenkomst, de dichtstbijzijnde buren.
- Twee pagina’s horen bij elkaar als ze allebei bij de ander in die twee staan.
- Een groep is een aaneengesloten keten van zulke paren. Een pagina zonder zo’n paar blijft los.
Met --buren kies je een ander aantal buren. Meer buren geeft grotere groepen.
Op die site gaf de regel 6 groepen van twee of drie pagina’s en 9 losse pagina’s.6 De indeling komt uit de embeddings; in de tabel noem ik per groep alleen het soort pagina’s.
De groepen van de voorbeeldsite
Per groep het aantal pagina’s, het aantal woorden en de laagste overeenkomst tussen twee pagina’s van de groep.
| Groep | Pagina’s | Woorden per pagina | Laagste overeenkomst |
|---|---|---|---|
| Blogs over een eerste thema | 3 | 730 tot 826 | 0,93 |
| Dienstpagina’s | 3 | 421 tot 664 | 0,93 |
| Blogs over een tweede thema | 2 | 1.205 tot 1.310 | 0,91 |
| Blogs over een derde thema | 2 | 1.383 tot 1.440 | 0,93 |
| Blogs over een vierde thema | 2 | 1.141 tot 1.206 | 0,92 |
| Een casepagina en een productpagina | 2 | 793 tot 1.239 | 0,92 |
Schuif opzij voor alle kolommen →
Eigen meting RankFellow · 23 pagina's · september tot oktober 2026
Los staan de homepage, de pagina met het aanbod, het blogoverzicht, het overzicht van de cases, het overzicht van de dienstpagina’s, de pagina over de eigenaar, een casepagina, de pagina van een tool en nog één blog.
Controle. Lees per groep de titels. Gaan ze over hetzelfde onderwerp, dan klopt de groep. Valt er een pagina uit de toon, kijk dan of de tekst die je naar het model stuurde echt de hoofdtekst was.
5. Tel per groep de links in de tekst
Google gebruikt links als signaal voor de relevantie van pagina’s en om nieuwe pagina’s te vinden.7 Ik tel alleen de links in de tekst, omdat links in het menu en de voettekst op bijna elke pagina staan en dus niets zeggen over welke pagina’s bij elkaar horen.
- Exporteer in Screaming Frog Bulk Export, Links, All Inlinks.
- Geef het bestand aan het script met
--links.
Het script houdt de hyperlinks over met Link Position Content, de plek die Screaming Frog aan links in de hoofdtekst geeft. Daarnaast laat het een link weg als 60% of meer van de pagina’s naar hetzelfde adres linkt, en zo’n link behandel ik als menu of vast blok.8 Dat getal en de 500 tekens uit stap 1 zijn mijn keuzes; je past ze aan met --sjabloon en --min-tekens.
Daarna telt het script per groep de links tussen de pagina’s van die groep. Bij groepen van drie of meer noemt het de centrale pagina, of meldt het dat alle pagina’s naar elkaar linken. Een centrale pagina is een pagina die naar alle andere pagina’s van de groep linkt of door alle andere gelinkt wordt, zoals een overzichtspagina (hub-pagina) dat doet.
Controle. Neem één groep en kijk op de pagina’s zelf of de getelde links in de tekst staan.
6. Leg de vertoningen ernaast en lees af wat ontbreekt
Exporteer in Search Console onder Prestaties, Zoekresultaten het tabblad Pagina’s over de laatste 28 dagen, en tel per groep de vertoningen van de pagina’s op.
| Groep | Links in de tekst onderling | Vertoningen in 28 dagen |
|---|---|---|
| Blogs over een eerste thema | 2 van 6 | 0 |
| Dienstpagina’s | 6 van 6 | 84 |
| Blogs over een tweede thema | 2 van 2 | 22 |
| Blogs over een derde thema | 2 van 2 | 0 |
| Blogs over een vierde thema | 0 van 2 | 6 |
| Een casepagina en een productpagina | 1 van 2 | 23 |
Eigen meting RankFellow · 23 pagina's · 9 september tot en met 6 oktober 2026
Nul vertoningen zegt alleen dat de pagina’s niet in beeld komen, niet dat er content ontbreekt. Dat lees je af aan vier signalen, die volgen uit mijn werkwijze voor deze stap.
- Een overzichtspagina. Een groep van drie of meer pagina’s zonder centrale pagina. Op de voorbeeldsite is dat de groep blogs over het eerste thema, met 2 van de 6 mogelijke links en geen vertoningen in 28 dagen. Of je dan een overzichtspagina bouwt of een bestaande pagina verdiept, staat in Pillar-pagina of hub, wanneer bouw je een overzichtspagina?.
- Links in de tekst. Twee pagina’s die bij elkaar horen maar niet naar elkaar linken, zoals de twee blogs over het vierde thema.
- Verdieping. Een korte pagina die relatief veel vertoningen krijgt. Het script noemt een pagina kort als hij minder woorden heeft dan de helft van de mediaan, het middelste aantal woorden van de pagina’s in je bestand. Op de voorbeeldsite is dat de pagina over de eigenaar, met 341 woorden en 66 vertoningen in 28 dagen, van de losse pagina’s het meest na de homepage.9 Op welke zoektermen hij verschijnt, heb ik voor dit stuk niet bekeken; zijn het zoekopdrachten op de naam van de eigenaar, dan voegt verdieping weinig toe.
- Een ontbrekend onderwerp. Een onderwerp van je onderwerpenlijst waar geen groep en geen losse pagina over gaat.
Voor dat laatste leg je je onderwerpenlijst uit stap 5 van de gids naast de groepen. Bij een korte lijst zoek je per onderwerp met de hand de groep die erbij hoort, op de titels. Bij een lange lijst maak je ook van elk onderwerp een embedding, van de naam en de zoektermen, en zoek je de pagina die er het dichtst bij ligt. Mijn systeem doet iets verwants in de module content coverage. Het vergelijkt de embeddings van de eigen pagina’s met groepen tussenkoppen en vragen uit de SERP.
Je kunt een taalmodel per groep de titels en de eerste alinea’s geven en het laten voorstellen over welk onderwerp de groep gaat. De indeling zelf laat ik op de embeddings rusten en niet op het oordeel van zo’n model.
Controle. Elk onderwerp van je lijst heeft een groep, een losse pagina of het label ontbreekt.
Het script
groepeer_paginas.py doet stap 3, 4 en 5 in één keer. Het leest de CSV uit stap 2 en, als je die meegeeft, de export All Inlinks.
python groepeer_paginas.py vectoren.csv --links all_inlinks.csv --uit groepen.csv
De mogelijkheden:
--buren, het aantal dichtstbijzijnde buren, standaard 2;--min-tekens, pagina’s met minder tekst overslaan, standaard 500;--kort, je eigen grens voor korte pagina’s in woorden; zonder grens is dat de helft van de mediaan van de pagina’s in je bestand;--links, de export All Inlinks van Screaming Frog;--sjabloon, het aandeel pagina’s vanaf waar een link als menu of vast blok telt, standaard 0,60;--uit, de groepen ook naar een CSV schrijven.
Ik heb het getest op de embeddings en de links van de voorbeeldsite uit september en oktober 2026. Het gaf dezelfde groepen, dezelfde laagste overeenkomst per groep en hetzelfde aantal links als mijn berekening in BigQuery. Een deel van de uitvoer, met algemene adressen in plaats van de echte:
23 pagina's, 15 groepen, waarvan 6 met meer dan één pagina
Overeenkomst over alle paren: gemiddeld 0.84, laagste 0.67, hoogste 0.97
Kort: minder dan 400 woorden (de helft van de mediaan van 800 woorden)
Groep 1: 3 pagina's, laagste overeenkomst binnen de groep 0.93, links in de tekst onderling 2 van 6, centrale pagina: geen
example.com/blog/blog-1 (826 woorden)
example.com/blog/blog-2 (797 woorden)
example.com/blog/blog-3 (730 woorden)
Groep 2: 3 pagina's, laagste overeenkomst binnen de groep 0.93, links in de tekst onderling 6 van 6, alle pagina's linken naar elkaar
example.com/diensten/dienst-1 (445 woorden)
example.com/diensten/dienst-2 (421 woorden)
example.com/diensten/dienst-3 (664 woorden)
Groep 13: 1 pagina
example.com/over (341 woorden, kort)
Met de vier signalen uit stap 6 vul je in stap 6 van de gids de kolom Besluit van je onderwerpenlijst.
Veelgestelde vragen
Wat is de betekenis van "semantisch"?
Wat is een semantische relatie?
Wat zijn clusters?
Bronnen en eigen metingen
- 1Google Search Central (2025). A guide to Google Search ranking systems. Documentatie, engels. Gecontroleerd op 9 oktober 2026.
- 2Eigen meting RankFellow · 26 pagina's · september tot oktober 2026. 23 van 26 pagina's van een kleine zakelijke site met een embedding van 768 getallen hadden genoeg tekst (500 tekens of meer).
- 3Screaming Frog (2025). Screaming Frog SEO Spider Update (version 22.0). Documentatie, engels. Gecontroleerd op 9 oktober 2026.
- 4Screaming Frog (2025). Low Relevance Content. Documentatie, engels. Gecontroleerd op 9 oktober 2026.
- 5Eigen meting RankFellow · 23 pagina's · september tot oktober 2026. 0,84 gemiddelde cosinusovereenkomst tussen de embeddings van twee pagina's van een kleine zakelijke site, over 253 paren, met 0,67 als laagste en 0,97 als hoogste.
- 6Eigen meting RankFellow · 23 pagina's · september tot oktober 2026. 6 groepen van twee of drie pagina's en 9 losse pagina's, bij een groepering van een kleine zakelijke site op de embeddings van de pagina's.
- 7Google Search Central (2025). Link best practices for Google. Documentatie, engels. Gecontroleerd op 9 oktober 2026.
- 8Eigen meting RankFellow · 23 pagina's · crawl van 4 oktober 2026. 2 van 6 mogelijke links in de tekst tussen de drie pagina's van een groep blogs over één thema, zonder centrale pagina.
- 9Eigen meting RankFellow · 23 pagina's · 9 september tot en met 6 oktober 2026. 0 vertoningen in 28 dagen voor de drie blogs in een groep over één thema.
Verder in de gids
Welke onderwerpen mist je site nog?
Terug naar stap 6: Ontbrekende onderwerpen.
Kan Google alles ophalen, en krijgen je belangrijke onderwerpen genoeg gewicht?
Zorgen dat Google alles kan ophalen, begrijpen en snel laden, en dat de opbouw je belangrijke onderwerpen het meeste gewicht geeft.
Het hele proces in twaalf stappen
Het overzicht van alle stappen van de SEO/GEO-gids.
