062 —Frontend
Checkout-JavaScript auditen: 15 minuten via de network-tab
Een pass van vijftien minuten in de network-tab voor third-party scripts die je verouderde checkout nog laadt maar niemand in het team kan plaatsen.
Het is vrijdagmiddag 15:40 en een Magento 1 checkout doet er 6,2 seconden over tot first paint. De shopeigenaar mailde op woensdag. Je opent DevTools, schakelt over naar de Network-tab, filtert op JS, en telt 38 third-party scripts die afvuren voordat de betaalknop rendert. Ongeveer de helft kun je niet op het zicht plaatsen.
Dit is de audit-pass voor dat moment. Vijftien minuten van koude start naar een geschreven lijst van third-party JavaScript die vandaag van de pagina af kan, zonder dat je een build-pipeline, heatmap-leverancier of Lighthouse-rapport binnenhaalt.
Eén reload, één HAR-bestand
Open de checkout in een incognito-venster met cache uitgeschakeld (DevTools open, Network-tab, "Disable cache" aangevinkt). Filter het requests-paneel op JS via de type-selector. Hard reload. Het punt van incognito is dat je ingelogde admin-state en browser-extensies eruit haalt die anders de trace vervuilen.
Rechtsklik ergens in het requests-paneel en kies Save all as HAR with content. Dit is je audit-corpus. Je komt er de komende tien minuten drie of vier keer op terug, en je wilt geen live checkout blijven verversen terwijl het marketingteam meekijkt op het realtime-dashboard.
jq '.log.entries[]
| select(.response.content.mimeType | test("javascript"))
| .request.url' checkout.har | sort -uDat geeft je een gededupliceerde lijst van elke JS-URL op de pagina. Op een representatieve checkout zijn dat ergens tussen 25 en 80 regels.
Sorteer op initiator, niet op URL
De URL-kolom is misleidend. Een request van analytics.tiktok.com vertelt je dat het de TikTok-pixel is, maar niet wie hem daar heeft neergezet. De Initiator-kolom doet dat wel. Klik op de kolomkop om die toe te voegen als hij niet zichtbaar is.
Waar je naar zoekt zijn ketens: een script dat geladen wordt door een ander script dat geladen wordt door weer een ander script. In negen van de tien gevallen op een verouderde checkout zit de wortel van die keten op één van drie plekken:
- De
functions.phpvan het theme of het equivalent daarvan (WooCommerce hooks, Magento layout-XML). - Google Tag Manager of een vergelijkbare container-snippet die vijf jaar geleden in
<head>is geplakt. - De instellingenpagina van een plugin, waar een vorige ontwikkelaar een tracking-snippet in een "custom HTML"-veld heeft geplakt.
Initiator-ketens in DevTools laten je de call stack zien. Een script dat met gtm.js bovenaan zijn initiator verschijnt, wordt vrijwel zeker door een tag in je container geïnjecteerd, ook al kun je je niet herinneren dat je hem hebt toegevoegd. Open de container in een aparte tab en grep de gepubliceerde versie op het domein van het script. Je vindt tags waarvan de triggers verwijzen naar campagnes die in 2022 zijn afgelopen.
Drie patronen die elke redesign overleven
De wees-tag in Tag Manager
Iemand maakte ooit een tag genaamd "Marketing Pixel: Black Friday 2023" met een All Pages trigger. De campagne is zestien maanden geleden afgelopen. De tag vuurt nog steeds af op elke checkout en laadt 41 KB aan script vanaf een domein dat 200 teruggeeft, omdat de leverancier het al lang slapende account nog steeds factureert.
De plugin die je verving maar nooit volledig deïnstalleerde
WooCommerce levert een kerkhof aan deze gevallen. Een vorige ontwikkelaar activeerde een coupon-plugin, vond hem niet passen en deactiveerde hem. De tracking-call van de plugin staat nog steeds in wp_options, omdat de uninstall-hook nooit gedraaid heeft. De volgende theme-update schreef een transient die de oude call bevat. Nu is hij onderdeel van elke checkout-render.
Een snelle check met de MySQL-editor:
SELECT option_name, LEFT(option_value, 200)
FROM wp_options
WHERE option_value LIKE '%hotjar%'
OR option_value LIKE '%fbq(%'
OR option_value LIKE '%gtag(%';Op een vijftien jaar oude WordPress-installatie geeft deze query vier tot tien rijen terug. De meeste zijn slapend.
Het "we halen het weg na de test"-script
Een consultant voegde in 2024 een session-replay script toe voor twee weken UX-onderzoek. Het snippet in het theme heeft hij weggehaald. De regel in de WPRocket excludes-lijst niet, en die zegt nog steeds tegen de pagina dat hij de CDN van de leverancier moet preloaden. Die handshake kost je 80ms op elke checkout in drie landen.
Houden, deferren, verwijderen
Schrijf bij elk script op de lijst één van drie letters: K, D, X.
- K (keep): het script is echt nodig voor de checkout (SDK van de betaalprovider, fraudecheck, consent banner). Laat het staan, maar check of het van
<head>naar net voor</body>kan verhuizen. - D (defer): marketing wil het, maar de pagina werkt ook zonder. Voeg
deferofasynctoe, of zet het achter de consent-gate waar het sinds de AVG al hoorde te staan. De MDN-referentie over script loading is de one-pager met de trade-offs. - X (verwijder): niemand is eigenaar, niemand leest de data. Haal het uit de bron en voeg vervolgens een defensieve Content-Security-Policy-regel toe zodat het niet via een plugin-update terugkomt.
Voor de X-bucket houdt een aanvullende .htaccess-regel elke plugin zichtbaar die hetzelfde domein stilletjes opnieuw probeert in te voeren:
<IfModule mod_headers.c>
Header always set Content-Security-Policy "script-src 'self' 'unsafe-inline' https://js.stripe.com https://www.googletagmanager.com; report-uri /csp-report.php"
</IfModule>Dit is het deel dat de meeste audits overslaan. Het script vandaag verwijderen weerhoudt het marketingteam er niet van om het volgende week opnieuw via de GTM-webinterface toe te voegen. De CSP maakt die toevoeging zichtbaar: het script wordt door de browser geblokkeerd, het report-endpoint logt de poging, en op maandag heb je een gesprek.
Een tweede pass om de winst te bevestigen
Hard reload, exporteer de HAR opnieuw, draai het jq-commando nog eens. Het aantal regels moet dalen. Op de checkout van een representatieve verouderde site die we vorige maand auditten, ging het aantal van 53 JS-requests naar 31, en de first paint van 6,2s naar 3,4s. Het kopcijfer is mooi. Wat ervoor zorgt dat de wijziging de volgende theme-update overleeft, is de schriftelijk afgetekende lijst met verwijderingen.
Dezelfde pass, op hetzelfde type site, elke week
Toen we Pier bouwden, zagen we precies deze audit telkens terugkomen bij klanten. De MySQL-grep op slapende tracker-strings, de archeologie in de GTM-container, de versiegeschiedenis-entry vastgepind op "Hotjar verwijderd 2024-09-23, marketing bevestigt geen actief account." De manier waarop we het uiteindelijk hebben opgelost: de bonnetjes blijven in dezelfde chatomgeving waar ook de edits gebeuren, zodat de audit en de diff op één plek leven.
Heb je vandaag maar tien minuten, exporteer dan de HAR van één checkoutpagina en grep hem op drie stringfragmenten: hotjar, tiktok en fbq(. Alles wat raak is, is een kandidaat. De rest van de audit kan wachten tot maandag.
— Vragen —
Kan ik deze audit draaien zonder dat DevTools de hele tijd open hoeft te staan?
Ja. Exporteer een HAR-bestand vanuit elke browser die het formaat ondersteunt en draai vervolgens jq-filters offline. De HAR is je audit-corpus en overleeft reboots, dus de live checkout krijgt de last maar één keer te verwerken.
Wat als de audit een tracker vindt die marketing nog wil houden?
Zet hem op defer, async of achter de consent-banner. Het doel van de pass is gewicht weghalen uit het kritieke render-pad, niet elk script verwijderen waar de business iets aan heeft.
Hoe vaak moet deze audit op een productie-checkout draaien?
Na elke theme-update, plugin-installatie of campagnelancering vanuit marketing. Prik daarnaast één keer per maand een terugkerend agendablok als vangnet voor degene die zonder deploy doorglippen.