Interaction to Next Paint (INP) is een nieuwe performance indicator die een aanzienlijke invloed heeft op je zoekresultaten (SERP). Maar hoe werkt het en hoe kunnen we het meten en debuggen om de INP van onze website te verbeteren?
Core Web Vitals is een initiatief van Google dat een reeks statistieken gebruikt om de gebruikerservaring op een website te meten. Vanaf maart 2024 vervangt Interaction to Next Paint (INP) de First Input Delay (FID) als een Core Web Vital om de responsiviteit van een website te meten. Waar FID de invoervertraging van de eerste interactie met een pagina mat, neemt INP alle interacties binnen een gebruikerssessie in overweging.
Zie hieronder een afbeelding van Google die illustreert wat een "interactie" en een "paint" is, samen met een video van een voorbeeld van goede en slechte responsiviteit:
INP zou een betrouwbaardere statistiek moeten zijn om de responsiviteit van een website tijdens gebruikersinteracties vast te leggen. Omdat INP gaat over echte gebruikersinteracties, wilde ik real-user monitoring (RUM) instellen rond INP. Dit is wat ik heb ontdekt.
Hoe Interaction to Next Paint verschilt van andere statistieken
De andere Core Web Vitals, zoals Largest Contentful Paint en Cumulative Layout Shift, zijn voornamelijk statistieken voor de eerste laadtijd, wat betekent dat ze de eerste indruk van een pagina meten. Aangezien INP echte gebruikersinteracties tijdens een sessie meet, is het veel moeilijker om INP in een gecontroleerde, gesimuleerde omgeving te meten. INP is afhankelijk van gebruikersinteractie, wat betekent dat een gebruiker op de website moet klikken, typen of scrollen om INP te meten. Het is lastig om alle mogelijke interacties in synthetische tests te triggeren, en handmatig alle mogelijke interacties uitvoeren kost veel tijd. Daarom is het logisch om Real User Monitoring (RUM)-gegevens te gebruiken om INP-waarden te monitoren. Later kun je proberen die langzame interacties in een gecontroleerde omgeving te reproduceren.
Er zijn uitstekende tools beschikbaar voor performance monitoring die ook INP in de praktijk meten, maar het doel hier was om mijn eigen tool te bouwen om een beter begrip te krijgen van INP en hoe je dit kunt meten.
Laten we dus eens kijken naar het meten van INP in de praktijk.
Hoe meet je INP?
INP wordt gemeten met behulp van de Event Timing API en specifiek de Performance Event Timing interface.
We kunnen een script op elke pagina laden, zoals dit:
let largestINPValue = 0;
new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
if (entry.duration > largestINPValue) {
largestINPValue = entry.duration;
console.log(`[INP] duration:
${entry.duration},
type: ${entry.name}`,
entry
);
}
}
}).observe({
type: 'event',
buffered: true
});
Nu zal de INP-waarde worden gelogd in de console bij elke interactie die groter is dan de eerder geregistreerde INP-waarde. Dit doen we om te voorkomen dat we onszelf overladen met INP-interacties. We zouden hier ook iets kunnen doen met het rapporteren van waarden die als "slecht" of "verbetering nodig" worden beschouwd.
Zie hieronder een schermopname van INP-waarden die in de console worden gelogd:
Wat ook handig is voor het opsporen en daadwerkelijk oplossen van INP-problemen, is de Long Animation Frame API (LoAF). De LoAF geeft je gedetailleerde informatie over hoe de tijd is besteed en welk script verantwoordelijk was voor de INP-waarde. Dat zou er als volgt uitzien:
const observer = new PerformanceObserver((list) => {
console.log(list.getEntries());
});
observer.observe({ type: "long-animation-frame", buffered: true });
Het lastige hier is dat we zowel INP als lange animatieframes moeten meten om de INP-entry met de LoAF-entry te matchen om de toewijzingsgegevens voor de INP-entry te krijgen.
Als je niet in de details van de onderliggende Web API's wilt duiken en gewoon wilt dat dit werkt, is er het geweldige npm-pakket web-vitals, dat de implementatie voor je vereenvoudigt. Vooral het koppelen van de INP-gegevens aan hun toewijzing is een beetje omslachtig, dus web-vitals
is hier echt handig. Het bovenstaande, met toewijzing, zou er als volgt uitzien:
import { onINP } from 'web-vitals/attribution';
onINP((data) => {
console.log(`
[INP] duration:
${data.value},
type: ${data.entries[0].name}`,
data.entries[0]
);
}, {reportAllChanges: true});
Real User Metrics (RUM) verzamelen
In plaats van de gegevens naar de console te loggen, kunnen we ze nu naar onze analyticsprovider sturen of waar je de gegevens ook maar wilt opslaan. Omdat we de INP-waarden per pagina en per gebruiker willen verkrijgen, sturen we met de pagina URL een unieke identificatiecode mee voor de gebruiker. Deze zijn handig wanneer we de gegevens later verwerken.
Onze reportINP
-implementatie zou er ongeveer zo uitzien:
import { onINP } from 'web-vitals/attribution';
let sessionId = sessionStorage.getItem('session-id');
if (!sessionId) {
sessionId = uuid();
sessionStorage.setItem('session-id', sessionId);
};
onINP(({.value. attribution }) => {
reportINP({
value,
attribution,
sessionId,
})
}, {reportAllChanges: true});
Alles ziet er goed uit, maar zoals altijd is er een addertje onder het gras...
Overwegingen
Tijdens het verzamelen van RUM-gegevens wilde ik dit op onze eigen website implementeren. Bij het instellen en inloggen in de console kwam ik een paar zaken tegen om rekening mee te houden:
Browserondersteuning
Het meten van INP vereist de PerformanceEventTiming API. Deze web-API wordt niet ondersteund in Safari, wat betekent dat het niet mogelijk is om INP in Safari te meten. Dat betekent dat in Nederland ongeveer 24% van je gebruikers niet in je testresultaten zal worden opgenomen. Ik denk echter dat als je voldoende gegevens verzamelt, je nog steeds een goed inzicht krijgt in de algehele responsiviteit van je website. Het is ook belangrijk om te weten dat de andere core web vitals, Largest Contentful Paint en Cumulative Layout Shift, ook worden gemeten met behulp van web-API's die niet worden ondersteund in Safari, wat betekent dat het niet mogelijk is om RUM-gegevens te verzamelen in niet-Chromium browsers met de web-API's die bedoeld zijn voor deze metingen.
Een opmerking over single-page applications of hybride toepassingen
Onze website is gebouwd met Nuxt, en sommigen van jullie hebben misschien gehoord van Next.js, dat enorm populair is bij webontwikkelaars. Frameworks zoals deze serveren de gebruiker een volledig gerenderde HTML-pagina bij de eerste keer laden, maar gedragen zich daarna als een single-page application voor elke volgende pagina. Dit gedrag wordt "soft navigation" genoemd. In plaats van de hele pagina op te vragen via een URL, laadt de applicatie alleen de extra benodigde bronnen voor de volgende pagina. De URL in de browser wordt daarbij herschreven. Alle performance statistieken worden gemeten ten opzichte van de top-level paginanavigatie, wat betekent dat als we gebruikmaken van soft navigations, de statistieken niet per pagina worden gereset, waardoor het erg moeilijk wordt om core web vitals RUM-gegevens per pagina te verkrijgen.
De toekomst ziet er echter rooskleurig uit! Om deze uitdagingen op te lossen, wordt er gewerkt aan een soft navigation specificatie. Daarnaast zal het mogelijk worden om soft navigations te rapporteren met behulp van performance observers. Het zou er als volgt uitzien, geleend van Experimenting with measuring soft navigations:
const observer = new PerformanceObserver(console.log);
observer.observe({ type: "soft-navigation", buffered: true });
Let ook op dat er een soft-navs branch in de web-vitals repository bestaat, waarin het rapporteren van soft navigations al is geïmplementeerd.
Conclusie
Gerelateerde blog posts
Hoe maak je jouw meertalige website geschikt voor RTL met alleen HTML en CSS
Door DeclanFront-end at the Edge
Door VeraFull-stack Front-end
Door Jasper