Dit project is beveiligd. Voer de toegangscode in om de case study te bekijken.
Onjuiste code. Probeer het opnieuw.
← Terug naar overzichtDrie meetinstrumenten. Eén conclusie; en die lag niet waar de klant hem verwachtte.
Zet deze modus aan om de beoordelingscriteria in de tekst te highlighten.
Je maakt bij de opdracht duidelijk wat er van je gevraagd wordt en welke doelen jouw bijdragen dienen te bereiken.
Je formuleert heldere conclusies waar bruikbare verbetersuggesties uit voortvloeien.
Je verantwoordt gemaakte keuzes en resultaten pro-actief en helder naar belanghebbenden.
Je vergelijkt verschillen tussen praktijk en opleiding en onderbouwt naar welke aanpak de voorkeur uitgaat.
De aanleiding van dit onderzoek kwam vanuit frustratie. CompleetFit is een klant van Like Bamboo, en wij hosten hun WordPress-website. Deze specifieke klant is behoorlijk veeleisend, en hij trok bij LikeBamboo aan de bel met één hele duidelijke klacht: de website voelde veel te traag.
En dat was geen overdrijving. Als je de URL intikte en op enter drukte, duurde het echt bizar lang voordat je überhaupt op de website terechtkwam. En was je eenmaal binnen? Dan voelde het scrollen door de pagina of doorklikken naar een volgend scherm alsof je internet traag was hoewel de connectie prima was. De website was simpelweg enorm traag.
Waar de opdracht in eerste instantie voelde als "fix even dat de site sneller laadt", heb ik direct gekeken naar de onderliggende noodzaak: we moesten weten wát er precies fout ging. Aan mij is toen de vraag neergelegd vanuit Like Bamboo: doe een diepgaande audit, zoek uit waar de bottlenecks exact zitten, en kom met een gerichte oplossing.
Doelstelling:("hij is traag") omzetten in harde data, de root-cause van de vertraging (of dat nou code, hosting of plugins was) onweerlegbaar aantonen, en oplossingen presenteren die dit meetbaar en effectief zouden oplossen.
BC 8.4.1
Robert heeft mij ooit als feedback gegeven: "theorie is leuk, maar hoe weeg je het af?".
Ik had grofweg vier oplossingsrichtingen om de render-blocking en codebase-problematiek aan te vliegen. Omdat de site bij Like Bamboo live in productie draait, stond stabiliteit voorop:
Met één meetinstrument kun je toevallig een vertekend beeld krijgen. Daarom heb ik er bewust drie ingezet — dat heet triangulatie. De logica is simpel: als drie totaal verschillende methodes naar dezelfde conclusie wijzen, dan weet je vrij zeker dat het klopt.
De eerste stap: Google's eigen gratis audit-tool, PageSpeed Insights. Die geeft een score van 0 tot 100 op vier categorieën. Ik heb bewust zowel de mobiele als de desktop versie gedraaid — want die kunnen flink van elkaar verschillen.
Die 100 op prestaties is natuurlijk nep. De server stuurt namelijk een 403 Forbidden naar de Lighthouse-crawler. PageSpeed meet hierdoor alleen een lege, razendsnelle foutpagina. Maar wat erger is: deze zelfde strenge blokkade geldt direct ook voor Googlebot, waardoor de site simpelweg niet goed geïndexeerd kon worden.
Omdat de externe audit faalde door de 403 foutmelding, ben ik de interne laadtijden gaan meten met de JavaScript Performance API in de browser. Dit is tenminste échte gebruikersdata in plaats van een gesimuleerd web-lab.
| Metriek | Desktop | Mobiel | Norm |
|---|---|---|---|
| TTFB | 5.000 ms | 3.636 ms | <800 ms |
| First Paint | 5.192 ms | — | <1.800 ms |
| DOM Interactive | 5.215 ms | 3.706 ms | <3.000 ms |
| DOM Content Loaded | 5.257 ms | 3.736 ms | <3.000 ms |
| Full Page Load | 5.762 ms | 4.170 ms | <3.000 ms |
Tot slot wilde ik weten wát de browser precies allemaal aan het downloaden is. Met een stukje JavaScript heb ik alle bestanden in kaart gebracht die de homepage laadt — elk script, elke stylesheet, elke afbeelding, elke video. Even de motorkap opentrekken, zeg maar.
Dit zijn diensten van andere bedrijven die op de achtergrond meedraaien. De bezoeker ziet er niks van, maar ze vreten wel laadtijd.
| Dienst | Wat het doet | Extra laadtijd |
|---|---|---|
| Google Tag Manager | Verzamelt bezoekdata + stuurt advertenties aan | +200-500ms |
| Facebook Pixel | Volgt bezoekers voor Facebook-advertenties | +200-400ms |
| LinkedIn Insight | Volgt bezoekers voor LinkedIn-advertenties | +100-300ms |
| Ahrefs Analytics | SEO-analysetool | +100ms |
| Trustindex.io | Toont Google Reviews op de site | +200ms |
| Google Ads Conversie | Meet of advertentieklikken tot klanten leiden | +200ms |
Een afbeelding hoeft niet groter te zijn dan het vakje waarin-ie wordt getoond. Hier een overzicht van hoe ver de afbeeldingen op de CompleetFit site afwijken:
| Bestand | Werkelijke grootte | Weergave op scherm | Te groot factor |
|---|---|---|---|
| DSC_2729.jpg | 1920×1280 | 452×301 | 18,1× |
| CompleetFit-Logo-Wit-1.png | — | klein | 9,2× |
| Group-29@2x-1.png | 537×123 | 181×42 | 8,7× |
| CompleetFit-Nijmegen-*.jpg | 1600×1600 | 624×624 | 6,6× |
Geen enkele afbeelding heeft
loading="lazy". Dat betekent: álles wordt direct gedownload, ook plaatjes die helemaal onderin de
pagina staan en die je misschien nooit te zien krijgt.
| Onderdeel | Detail | Probleem |
|---|---|---|
| CMS | WordPress 6.8.5 + Divi v4.27.4 | Divi genereert 225 extra HTML-elementen |
| Video's | 7 autoplay MP4 bestanden | Laden direct mee, kosten veel data |
| Fonts | Neuzeit Grotesk + Neusa Next (Adobe Typekit) | Extra DNS-lookup + render-blocking CSS |
De technische audit toonde aan dat de laadvertraging breed gedragen werd door zes knelpunten. Om actie af te dwingen heb ik drie scherpe conclusies getrokken die direct in de roadmap moesten komen.
De veiligheidsplugin van Wordfence blokkeerde de test-crawlers én Googlebot met een 403 Forbidden. Google analyseerde hierdoor een lege snelle 403-foutpagina (vandaar de 100/100 fake score), wat een complete ramp qua SEO bleek te zijn.
Quick-winGooglebot onmiddelijk whitelisten in de Wordfence firewall instellingen. Een handeling van nog geen vijf minuten die zowel de valse rapportages als de SEO-blokkade in één keer wegnam.
De werkelijke TTFB fluctueerde bizar hard tussen de 3,6 en 5.2 seconden (norm = < 800ms). Het diepere probleem is de logge pagebuilder Divi die 739 DOM nodes inlaadt op goedkope budget hosting. Elke vorm van image-optimalisatie is nutteloos zolang de HTML zelf zo laat reageert.
Quick-winDatabase overhead reduceren door server-side full page caching structureel toe te passen in combinatie met Cloudflare CDN. Verwachte Time-to-first-byte reductie: -3,5 seconden.
Foto's worden op 1920px ingeladen voor vakjes van 400px breed (ongeveer 18x te zwaar) zonder luie laadtijd. Minimaal 10 CSS modules blokkeren hard de initiële render, terwijl 22 losse third-party tracking scripts synchroon meeslurpen aan de bandbreedte.
Structureel adviesPas Autoptimize toe om render-blocking resources via CSS samenvoeging en inline font-display: swap methodieken ongedaan te maken. Gebruik een tagmanager proxy voor de asynchrone lading van alle non-essentiële marketing pixels.
Na het rapport met rode cijfers was de keuze simpel: dichtklappen of doorpakken. Ik koos het tweede. Hieronder de concrete realisatie — elke ingreep direct gekoppeld aan het ontwerpdoel: Perceived Performance herstellen.
Eerst even het olifantje in de kamer. Die 100/100 van Google PageSpeed Insights? Compleet verzonnen door de server zelf. De Wordfence-firewall gooide de deur dicht voor elke crawler — inclusief Googlebot. Dus PageSpeed Insights mat braaf een lege 403-foutpagina, gaf daar een perfecte score aan, en iedereen was tevreden. Behalve de bezoeker die zes seconden naar een wit scherm zat te staren, uiteraard.
Om écht te meten wat die site deed, moest ik onder die firewall door kruipen. Via een lokale headless Lighthouse-audit — Chrome opstarten zonder venster, rechtstreeks vanuit de terminal — kon ik de blokkade omzeilen. De crawler gedroeg zich als een reguliere bezoeker, Wordfence liet hem door, en voor het eerst hadden we eerlijke cijfers.
Die eerlijke cijfers? Een performance score van 31 op 100. Geen oranje. Diep rood. De LCP — het moment waarop het grootste element op je scherm verschijnt — duurde bijna negen volle seconden. Negen. Je had in die tijd twee kopjes koffie kunnen inschenken.
Het lag voor de hand om bij de afbeeldingen te beginnen. Die DSC_2729.jpg van achttien keer te groot was het schoolvoorbeeld: een rauwe camerafoto van 1920×1280 pixels, gepropt in een vakje van 452×301. Niet te bevatten eigenlijk, dat soort dingen standaard zijn in WordPress als niemand oplet.
De Smush plugin deed precies wat-ie beloofde. Bulk-compressie over alle bestaande afbeeldingen — lossless, geen zichtbaar kwaliteitsverlies — plus het activeren van lazy loading. Dat laatste is misschien nog belangrijker dan de compressie zelf: afbeeldingen buiten je viewport worden pas opgehaald als je ernaar scrolt. Voorheen downloadde de browser álles in één keer, ongeacht of je het ooit zou zien.
Resultaat: het totale afbeeldingsgewicht daalde naar zo'n 648 KB per paginalading. Abstract getal, maar vergelijk het met de megabytes die er voorheen doorheen vlogen — dan snap je de omvang.
Dit irriteerde me eerlijk gezegd. De plugin stónd er al. WP Super Cache was geïnstalleerd maar half geconfigureerd. Alsof je een slot op de deur hebt laten zetten maar vergeet de sleutel om te draaien. De geavanceerde instellingen — paginacompressie via gzip, cache rebuild, uitgesloten caching voor beheerders — stonden allemaal uit.
Na het juist configureren serveerde de site gecachte pagina's als statieke HTML, waardoor de hele WordPress-database-dans werd overgeslagen. In plaats van elke keer PHP uitvoeren, databases raadplegen en alles opnieuw assembleren, stuurt de server gewoon een kant-en-klaar bestand terug. Of ja — dat zou-ie moeten doen. De TTFB bleef hardnekkig schommelen rond de twee seconden, wat vertelde dat de hosting zelf de bottleneck is, niet WordPress.
En toen de klapper. Van alle drie de ingrepen was dit diegene waarvan ik achteraf dacht: waarom doet niet iedereen dit standaard? Flying Scripts is een piepkleine plugin die externe JavaScript-bestanden uitstelt tot het moment dat een bezoeker interacteert — muisbeweging, scroll, toetsaanslag. Tot dat moment laadt het script simpelweg niet.
Ik configureerde vier trefwoorden:
googletagmanager — alle Google-trackers in één klap uitgesteldfbevents — de beruchte Facebook Pixel, die altijd mee wil laden alsof-ie de belangrijkste
gast op het feest isinsight.min — LinkedIn's tracking-scripttrustindex — de Google Reviews widget die een bezoeker toch pas ziet als die scroltHet effect was absurd. De Total Blocking Time — de periode waarin de browser zegt "even wachten, ik ben scripts aan het uitvoeren" — ging van 1.180 milliseconden naar letterlijk nul. Niet "bijna nul." Nul. De browser werd niet meer gegijzeld door trackers.
Na die eerste drie ingrepen stond de teller op 69/100. Best netjes. Maar iets knaagde. Als je de site opende — vooral op een wat trager netwerk — zag je nóg steeds een flits. Eentje die je bijna niet kon plaatsen: de tekst verscheen, verdween dan een fractie, en dook weer op in een ander lettertype. Alsof de pagina even van gedachten veranderde halverwege het opbouwen.
Dat fenomeen heeft een naam. Flash of Invisible Text (FOIT) — de browser wacht met het tonen van tekst totdat het externe lettertype volledig is gedownload. Bij CompleetFit ging het om Adobe Typekit-fonts die via een apart CSS-bestand worden opgehaald. Zolang dat bestand niet binnen is, zie je: niks. Leegte waar tekst hoort te staan.
Tegelijkertijd lag er nog een ander slepend probleem. De audit uit de vorige ronde had al 10 render-blocking CSS-bestanden gespot — Divi, Divi Pixel, Trustindex, Typekit, noem maar op. Ik had de tracker-scripts aangepakt met Flying Scripts, maar die stylesheets? Die stonden er nog steeds. De browser wachtte braaf tot alle tien geladen waren voordat hij ook maar één pixel tekende.
De oplossing was Autoptimize, dezelfde tool die ik in Fase 2 al had afgewogen tegen de alternatieven. Twee specifieke ingrepen:
font-display: swap geforceerd op alle externe lettertypes. Dat betekent:
de browser toont direct een systeemlettertype als placeholder, en wisselt geruisloos naar het Adobe-font
zodra dat geladen is. De bezoeker ziet per direct tekst — geen FOIT meer.De resultaten van deze vierde stap alleen al:
| Metriek | Nulmeting | Na ronde 1 | Na ronde 2 | Totaal |
|---|---|---|---|---|
| Performance Score | 31 | 69 | 72 | +41 punten |
| FCP (First Contentful Paint) | 6,6 s | 0,8 s | 2,6 s* | ↓ 61% |
| LCP (Largest Contentful Paint) | 8,9 s | 1,6 s | 1,6 s | ↓ 82% |
| Total Blocking Time | 1.180 ms | 0 ms | 0 ms | ↓ 100% |
| Speed Index | 15,4 s | 5,4 s | 5,4 s | ↓ 65% |
| Best Practices | 58 | 100 | 100 | +42 punten |
| SEO Score | 40 | 92 | 92 | +52 punten |
| Render-blocking CSS | 10 | 10 | 0 | ↓ 100% |
| FOIT Lettertypes | 5 | 5 | 0 | ↓ 100% |
| Afbeeldingsgewicht | >2 MB | 648 KB | 648 KB | ↓ ~70% |
* FCP in ronde 2 is hoger doordat de meting nu inclusief volledige TTFB serverwachttijd verloopt — de browser tekent direct na ontvangst, zonder extra blocking.
72 op 100. Is dat een bliksemschitterende score? Eerlijk gezegd: nee. Maar pak de reisweg erbij — van 31 via 69 naar 72, over twee optimalisatierondes met vier gratis WordPress-plugins — en je begrijpt hoever we gekomen zijn zonder ook maar één euro uit te geven. De bezoeker die voorheen bijna negen seconden wachtte op de hoofdafbeelding? Die ziet nu in anderhalve seconde een compleet scherm. Dat is het verschil tussen wegklikken en blijven hangen.
Wat me na de tweede ronde opviel — en dit is eerlijk een beetje frustrerend — is dat elke volgende punt harder gaat. Het verschil tussen 31 en 69 was spectaculair, bijna makkelijk zelfs. Maar van 69 naar 72? Dat kostte net zoveel denktijd voor drie schamele punten. De wet van de afnemende meeropbrengst in actie, zeg maar.
En dat brengt me bij de kern: wat er nu overblijft is niet met plugins op te lossen. De TTFB schommelt nog steeds rond de 3 seconden — dat is puur de hosting die het niet trekt. Google's grens voor een "goede" TTFB ligt op 600 milliseconden. Je kunt het frontend nog zo strak optimaliseren, als de server er drie seconden over doet om überhaupt te antwoorden, dan start je elk rapport met een handicap.
De Cumulative Layout Shift is daarnaast iets verslechterd doordat Smush lazy loading activeert zonder dat Divi vaste afmetingen meegeeft aan de afbeeldingscontainers. Dat verspringen ken je wel: je begint te lezen en dan schuift alles ineens een stuk naar beneden omdat er een plaatje inlaadt. Irritant, maar oplosbaar — mits je bij de broncode kan. En bij Divi is dat altijd een gevecht.
Wil CompleetFit structureel boven de 80 komen, dan zijn er drie dingen nodig die buiten de scope van plugin-optimalisatie vallen: een CDN ervoor (Cloudflare, gratis), krachtiger hosting die de TTFB naar onder de seconde trekt, en vaste dimensies op álle afbeeldingscontainers om die CLS te fixen. Op de langere termijn is dat Divi-thema gewoon te lomp voor wat deze site nodig heeft. Maar dat — dat is een ander gesprek dan waar we mee begonnen.
De meest waardevolle les uit dit hele traject had niks met code te maken. Het was het besef dat een getal — of dat nou 100/100 is of 31/100 — pas iets betekent als je weet hoe het tot stand komt. Die fake 100 vertelde een verhaal dat compleet los stond van de werkelijkheid. Pas toen ik de methodiek wijzigde kwamen de échte cijfers boven water. Soms zijn de kleinste numerieke winsten de meest zichtbare verbeteringen in de gebruikerservaring.
De bezoeker merkt een wereld van verschil. Wat nu overblijft voelt als een nulmeting voor een volgend gesprek — eentje over hosting, over architectuur, over de vraag of een pagebuilder als Divi nog houdbaar is als snelheid ertoe doet. Maar dat is precies wat een goede audit hoort te doen: niet alles oplossen, maar glashelder maken wat er speelt en waar de grenzen van je eigen ingrepen liggen.
Op de CMD-opleiding is de mantra duidelijk: schrijf schone, custom code, houd je DOM-tree ondiep, werk mobile-first en zorg dat performance vanaf seconde één in je architectuur zit verweven. De praktijk bij Like Bamboo en CompleetFit bleek echter compleet anders. Omwille van budget en klantbeheergemak is de frontend in elkaar geklikt met Divi — een loeizware pagebuilder die zonder pardon honderden overbodige node-elementen en scripts inlaadt.
Mijn initiële CMD-instinct was: het fundament is verrot, we moeten het thema herbouwen. Echter, dat zou CompleetFit duizenden euro's kosten, wat financieel totaal onhaalbaar is voor hun omzet/ROI. Ik werd gedwongen om de 'praktiijk-aanpak' te prefereren boven de theorie: in plaats van de bron aanpakken, heb ik gekozen voor agressieve symptoombestrijding via caching en bestandsaggregatie (Autoptimize). Hoewel dit indruist tegen mijn theorie-idealen, besefte ik dat dit voor deze MKB-context wél veruit de verstandigste aanpak is. Goed werk afleveren in een agency-omgeving betekent niet altijd 'de perfecte code' schrijven, maar de business case van de klant accepteren en daar met beperkte middelen maximale impact binnen uithalen.