Beveiligd Datapunt

Dit project is beveiligd. Voer de toegangscode in om de case study te bekijken.

Onjuiste code. Probeer het opnieuw.

← Terug naar overzicht

Performance
Audit.

Drie meetinstrumenten. Eén conclusie; en die lag niet waar de klant hem verwachtte.

Performance Web Vitals WordPress Audit

Docentweergave (Criteria & Verantwoording)

Zet deze modus aan om de beoordelingscriteria in de tekst te highlighten.

BC 8.1.1

Je maakt bij de opdracht duidelijk wat er van je gevraagd wordt en welke doelen jouw bijdragen dienen te bereiken.

BC 8.3.2

Je formuleert heldere conclusies waar bruikbare verbetersuggesties uit voortvloeien.

BC 8.4.2

Je verantwoordt gemaakte keuzes en resultaten pro-actief en helder naar belanghebbenden.

BC 8.5.1

Je vergelijkt verschillen tussen praktijk en opleiding en onderbouwt naar welke aanpak de voorkeur uitgaat.

Van Onderbuik naar Data

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
CompleetFit Nijmegen homepage
CompleetFit homepage — above the fold (desktop)

Niet zomaar een plugin BC 8.4.2

Robert heeft mij ooit als feedback gegeven: "theorie is leuk, maar hoe weeg je het af?".

De Afwegingsmatrix: Architectuur van keuzes

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:

  • WP Rocket: De industriestandaard. Fantastisch, maar qua structurele licentiekosten onnodig hoog voor deze scope.
  • W3 Total Cache: Extreem krachtig, maar berucht om conflicts met de zware codebase van Divi Themes. Een onverantwoord risico voor de live omgeving.
  • Handmatige Native Code (Functions.php): Zelf de render-flows injecteren op child-theme basis. Theoretisch perfect, maar uren-technisch niet te factureren binnen de sprint scope.
  • Autoptimize (Gekozen): Open-source, bewezen veilig voor de Divi builder, en primair ontworpen met focus op CSS/JS aggregatie — precies de pain-point uit het waterfall report.

Drie meetinstrumenten, één waarheid

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.

Instrument 1: PageSpeed Insights

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.

Prestaties
100
Nep — meet 403 pagina
Toegankelijkheid
95
Goed
Praktische tips
96
Goed
SEO
40
Kritiek — 403 blokkade

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.

PSI Mobiel scores
PSI Mobiel — scores (7 apr 2026)
PSI SEO 403 error
SEO detail — 403 Forbidden + crawl blokkade

Instrument 2: Browser Performance API

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.

Desktop vs. Mobiel vergelijking

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

Instrument 3: Network & Resource Analysis

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.

Totaal bestanden
85
Alleen de homepage
Scripts
34
22 extern, 12 eigen
Render-blocking CSS
10
Blokkeren weergave
DOM elementen
739
Divi genereert 225 ervan

Externe scripts die meeladen

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

Afbeeldingen: veel te groot

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.

Overige bevindingen

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

Van data naar geprioriteerde actie BC 8.3.2

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.

1. De Snelheidstest Liegt (403 Blokkade)

Conclusie

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-win

Googlebot 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.

2. De Server is de Fundamentele Bottleneck

Conclusie

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-win

Database 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.

3. Front-end Obesitas (DOM & Scripts)

Conclusie

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 advies

Pas 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.

Theorie omgezet in code

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.

De nepscore ontmantelen

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.

Stap 1: Smush — de foto's aanpakken

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.

Stap 2: WP Super Cache — eindelijk goed instellen

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.

Stap 3: Flying Scripts — het gouden ei

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 uitgesteld
  • fbevents — de beruchte Facebook Pixel, die altijd mee wil laden alsof-ie de belangrijkste gast op het feest is
  • insight.min — LinkedIn's tracking-script
  • trustindex — de Google Reviews widget die een bezoeker toch pas ziet als die scrolt

Het 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.

Stap 4: Autoptimize — de laatste visuele vertraging wegsnijden

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:

  • CSS-aggregatie: De 10 losse stylesheets samengevoegd tot één bestand. Eén HTTP-request in plaats van tien. De browser hoeft nu niet meer tien afzonderlijke bestanden op te halen voordat hij mag beginnen met tekenen.
  • 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:

Render-blocking CSS
10 → 0
Alle bestanden geaggregeerd
FOIT Lettertypes
5 → 0
display: swap actief
FCP
2,6 s
Incl. serverwachttijd
Score
69 → 72
+3 extra punten

Het volledige plaatje — van nulmeting tot eindstand

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.

Performance
72
was: 31 → 69 → 72
Best Practices
100
was: 58
SEO
92
was: 40
TBT
0 ms
was: 1.180 ms

Het Evaluatie-Plafond BC 8.3.2

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.

Wat er nog nodig is

Vervolgstappen

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.

Eigen reflectie

Wat ik hiervan leerde

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.

Praktijk vs Opleiding

Idealisme vs. Realisme BC 8.5.1

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.

„We hadden geen Google rapport nodig om te voelen dat het traag was. Maar we hadden wél een eerlijke meting nodig om te bewijzen hoe traag — en om te laten zien dat het anders kan."

Volgende showcase

Making of: Design System