import { onLCP, onINP, onCLS, MetricWithAttribution } from 'web-vitals/attribution';
function sendToAnalytics(metric: MetricWithAttribution) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
rating: metric.rating,
delta: metric.delta,
id: metric.id,
// Piesa cheie: afli exact elementul buclucaș
target: metric.attribution?.interactionTarget || metric.attribution?.largestShiftTarget || '',
page: window.location.pathname
});
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/vitals', body);
} else {
fetch('/api/vitals', { body, method: 'POST', keepalive: true });
}
}
// Le înregistrăm cu atribuire completă
onLCP(sendToAnalytics);
onINP(sendToAnalytics);
onCLS(sendToAnalytics);Anul ăsta am fost nevoit să curăț scorurile de Web Vitals la un magazin online cu peste 45k de vizitatori unici pe zi. În Vercel Speed Insights totul arăta verde și frumos, dar când mă uitam în Google Search Console, aveam peste 30% din URL-uri marcate cu 'INP mai mare de 200ms'. Am pierdut două zile încercând să înțeleg de unde vine discrepanța.
Problemă e modul în care diversele unelte agregă datele. Când ai utilizatori pe telefoane mai vechi, conectați la rețele 4G mai slabe din provincie, experiența lor e la kilometri distanță de testele tale sintetice pe un MacBook M2.
De ce te păcălește Vercel Speed Insights
Nu mă înțelege greșit, Vercel Analytics e genial pentru un proiect la început. Îl activezi din două click-uri, nu scrii cod, își face treaba. Dar când crești, apar două probleme mari.
Prima e eșantionarea (sampling-ul). Dacă depășești limita gratuită, Vercel începe să taie din date sau îți cere bani buni pe fiecare milion de evenimente. A doua e lipsa contextului complet pe atribute. Degeaba îmi zice Vercel că am un INP prost la percentila p75, dacă nu-mi spune exact ce element din DOM a declanșat întârziera — a fost butonul de 'Adaugă în coș', meniul mobil sau vreun script terț de la un pixel de tracking?
Soluția mea: RUM simplu cu pachetul web-vitals v4
Am renunțat la dashboard-ul lor implicit și mi-am scris propriul tracker folosind librăria oficială web-vitals. O pun direct în layout-ul aplicației și trimit datele către un endpoint intern în mod asincron cu navigator.sendBeacon.
Trimitem doar percentilele rele sau toate evenimentele cu praguri, dar cel mai important: capturăm attribution. Adică afli selectorul CSS exact care a provocat layout shift-ul la CLS sau elementul pe care s-a făcut click la INP.
Trade-off-uri sincere: Vercel vs Custom RUM
- Vercel Analytics / Speed Insights: Merge perfect pentru landing page-uri sau SaaS-uri mici unde nu vrei să mentii infrastructură de date. Nasol când ai trafic mare și vrei să debughezi cazuri de nișă pe telefoane Android slabe.
- Custom RUM (web-vitals + PostHog / ClickHouse / endpoint propriu): Ai control total pe percentile (p75, p90, p99), vezi exact elementul buclucaș și costă de 10 ori mai puțin la volum mare. Partea proastă? Ai de scris vreo 50 de linii de cod, trebuie să-ți faci singur dashboar-ul în Grafana sau PostHog și adaugi încă ~2KB la bundle-ul JS de pe client.
După ce am făcut trecerea și am optimizat handler-ele de event pe mobile (am scos două scripturi grele de la un vendor de chat), INP-ul real la p75 a scăzut de la 280ms la 110ms. Trecerea asta s-a văzut direct în traficul organic în vreo trei săptămâni.
Voi ce folosiți în producție pentru monitorizarea reală a utilizatorilor? Vă bazați doar pe rapoartele lunare din CrUX sau colectați metricile în timp real?