דלגו לתוכן

Web Vitals

ב-Agent Analytics המארח, מפתחות cwv_* נשמרים על page_view. ב-core באירוח עצמי אותם מפתחות נשמרים על אירוע $web_vitals. המארח לא שומר $web_vitals.

POST /vitals ו-GET /vitals הן קריאות של המארח. האירוע קבוע ל-page_view.

data-track-vitals="true" מפעיל איסוף. data-track-vitals="false" מכבה אותו. סניפטי ההתקנה שמופיעים כברירת מחדל כוללים data-track-vitals="true". סניפט בלי המאפיין נשאר כבוי. התקנות opt-in קיימות שומרות על אותה משמעות של הדגל.

במארח, כל flush מתמזג ל-page_view האחרון של אותו session ואותו path. flush מאוחר דורס את המפתחות. ה-path שנשלח עם ה-vitals הוא ה-path שנלכד בתחילת אותו דף.

data-track-performance עדיין כותב perf_ttfb על page_view בתור responseStart - requestStart. זה לא cwv_ttfb.

הכותרת היא האחוזון ה-75 (p75) של טעינות הדף. השיטה היא nearest-rank: ממיינים את הערכים בסדר עולה, שוברים שוויון לפי event id, ולוקחים את הדירוג ceil(0.75 * n). דירוג 1 הוא הערך הקטן ביותר. התוצאה היא ערך שנצפה.

מדד Property יחידה הגדרה
LCP cwv_lcp ms, מספר שלם Largest Contentful Paint. מושמט אם הדף היה hidden לפני ה-first paint.
INP cwv_inp ms, מספר שלם Interaction to Next Paint. רשומות event מקובצות לפי interactionId. כל אינטראקציה תורמת את משך הזמן המרבי שלה. INP הוא האינטראקציה הגרועה ביותר אחרי שמתעלמים מאינטראקציה גבוהה אחת לכל 50 אינטראקציות.
CLS cwv_cls חסר יחידה, 3 ספרות אחרי הנקודה Cumulative Layout Shift. חלון הסשן הגדול ביותר: פער מתחת לשנייה, חלון של 5 שניות לכל היותר, בלי shifts עם hadRecentInput.
FCP cwv_fcp ms, מספר שלם First Contentful Paint. מושמט אם הדף היה hidden לפני ה-first paint.
TTFB cwv_ttfb ms, מספר שלם Time to First Byte. responseStart - max(activationStart, 0) של הניווט, נמדד מתחילת הניווט.

דפים שעברו prerender לא נמדדים.

Core Web Vitals הם LCP, INP ו-CLS. FCP ו-TTFB הם שני המדדים הנוספים בקריאה הזו. ההגדרות והסף הם לפי Web Vitals.

ערך הוא good כשהוא <= good_max, poor כשהוא > poor_min, ו-needs-improvement אחרת. דירוג ה-p75 משתמש באותו כלל על ה-p75. share משתמש באותו כלל על כל טעינת דף. השברים הם מ-0 עד 1, עם 3 ספרות אחרי הנקודה. המפתחות ב-share הם good, needs_improvement ו-poor. מחרוזת הדירוג משתמשת במקף (needs-improvement). מפתח ה-share משתמש בקו תחתון (needs_improvement).

מדד יחידה Good Needs improvement Poor
LCP ms <= 2500 <= 4000 > 4000
INP ms <= 200 <= 500 > 500
CLS חסר יחידה <= 0.1 <= 0.25 > 0.25
FCP ms <= 1800 <= 3000 > 3000
TTFB ms <= 800 <= 1800 > 1800

cwv_pass משתמש רק ב-LCP, INP ו-CLS. הוא true כש-p75 של LCP, INP ו-CLS כולם good. כש-n של INP הוא 0, ההחלטה משתמשת רק ב-LCP וב-CLS. cwv_pass הוא null כש-n של LCP הוא 0 או n של CLS הוא 0.

CLS ו-INP נאספים רק ב-Chromium. בדפדפנים אחרים המפתח חסר. הוא לא נשמר כ-0.

LCP, FCP ו-TTFB נכתבים כשהדפדפן מדווח על הרשומה. דפדפן שלא מדווח על הרשומה משמיט את המפתח. מפתח שהושמט אינו 0.

n הוא מספר שורות page_view בקבוצה שכללו את המדד. skipped הוא מספר שורות page_view בקבוצה שלא כללו אותו.

vital חסר הוא skipped, לא אפס. תצוגות של שינוי route יכולות להיות בלי LCP ו-FCP. דפדפנים שאינם Chromium חסרים CLS ו-INP. דף בלי אינטראקציה חסר INP. אין n מינימלי בקריאה הזו.

כשדגל ה-vitals דלוק, הטרקר יכול לשלוח שלושה מאפייני target:

Property Selector
cwv_lcp_target אלמנט ה-LCP
cwv_inp_target יעד האינטראקציה של INP
cwv_cls_target יעד ה-shift הגדול ביותר של CLS

כל ערך הוא CSS selector, אחרי trim, עד 200 תווים. השדות מכילים selectors בלבד: בלי תוכן טקסט ובלי URLs.

top_poor_targets מציג עד 5 selectors לפי count בקרב טעינות שדורגו poor למדד הזה. כל רשומה היא { target, count }. ל-FCP ול-TTFB אין שדה target, ולכן top_poor_targets הוא [].

Pro. חשבון free מקבל 403 עם error PRO_REQUIRED. ה-403 הזה לא נספר כקריאה. תגובה מוצלחת אחת נספרת כקריאה ממוטרת אחת. גוף ה-403 הוא אובייקט השגיאה הרגיל: error, message, ו-payment כשהקורא יכול לראות חיוב.

גוף JSON של POST /vitals, או אותם שדות כ-query parameters ב-GET /vitals:

שדה חובה ערכים
project כן שם הפרויקט
days לא חלון ימים במספר שלם
date_from לא YYYY-MM-DD
date_to לא YYYY-MM-DD
group_by לא device או path
limit לא ברירת מחדל 10, מקסימום 20. בשימוש כש-group_by הוא path.

האירוע הוא page_view. /query ו-/compare לא השתנו.

בלי group_by: שורה אחת, group הוא null. group_by device: group הוא mobile, tablet או desktop. group_by path: עד limit נתיבים לפי n, ממוינים לפי LCP p75 הגרוע ביותר. group הוא ה-pathname.

האחוזונים הם nearest-rank. המדגם מוגבל ל-200,000 אירועים. כשהמכסה נפגעת, התגובה עדיין 200, approximate הוא true, ו-caps נוכח. אחרת approximate הוא false ו-caps מושמט.

{
"project": "my-site",
"date_from": "2026-11-06",
"date_to": "2026-11-12",
"event": "page_view",
"group_by": null,
"percentile": "p75",
"percentile_method": "nearest_rank",
"approximate": false,
"thresholds": {
"lcp": { "unit": "ms", "good_max": 2500, "poor_min": 4000 },
"inp": { "unit": "ms", "good_max": 200, "poor_min": 500 },
"cls": { "unit": "unitless", "good_max": 0.1, "poor_min": 0.25 },
"fcp": { "unit": "ms", "good_max": 1800, "poor_min": 3000 },
"ttfb": { "unit": "ms", "good_max": 800, "poor_min": 1800 }
},
"rows": [
{
"group": null,
"cwv_pass": true,
"metrics": {
"lcp": {
"p75": 2100,
"rating": "good",
"n": 400,
"skipped": 20,
"share": { "good": 0.8, "needs_improvement": 0.15, "poor": 0.05 },
"top_poor_targets": [{ "target": "img.hero", "count": 4 }]
},
"inp": {
"p75": 180,
"rating": "good",
"n": 360,
"skipped": 60,
"share": { "good": 0.75, "needs_improvement": 0.2, "poor": 0.05 },
"top_poor_targets": [{ "target": "button.buy", "count": 3 }]
},
"cls": {
"p75": 0.08,
"rating": "good",
"n": 390,
"skipped": 30,
"share": { "good": 0.82, "needs_improvement": 0.12, "poor": 0.06 },
"top_poor_targets": [{ "target": "#main > .banner", "count": 2 }]
},
"fcp": {
"p75": 1600,
"rating": "good",
"n": 400,
"skipped": 20,
"share": { "good": 0.84, "needs_improvement": 0.12, "poor": 0.04 },
"top_poor_targets": []
},
"ttfb": {
"p75": 700,
"rating": "good",
"n": 400,
"skipped": 20,
"share": { "good": 0.78, "needs_improvement": 0.16, "poor": 0.06 },
"top_poor_targets": []
}
}
}
]
}

p75 ו-rating הם null כש-n הוא 0. rating הוא good, needs-improvement, poor, או null.

כלי ה-MCP המארח הוא web_vitals. הארגומנטים תואמים ל-/vitals: project, days, date_from, date_to, group_by ו-limit. תיאור הכלי כולל את הסף. p75 הוא הכותרת. תוצאת הטקסט מדפיסה, לכל מדד, את ה-p75 עם היחידה, את הדירוג, את ה-share של good / needs-improvement / poor, ואת n.

query ו-compare עדיין מקבלים cwv_* כמאפיינים מספריים. במארח, האירוע הוא page_view.

vitals נמצא ב-@agent-analytics/cli@0.5.41. הוא קורא לקריאת /vitals המארחת.

Terminal window
npx --yes @agent-analytics/cli@0.5.41 vitals <project> [--days N] [--from YYYY-MM-DD] [--to YYYY-MM-DD] [--by device|path] [--limit N] [--json]

--from ו---to הם date_from ו-date_to. --by הוא group_by. --limit ברירת מחדל 10 והמקסימום 20. --json מדפיס את גוף ה-API.

ב-2026-11-13, CLS ו-INP השתנו במקום (tracker 0.2.5).

לפני התאריך הזה, CLS היה סכום ערכי layout-shift בלי hadRecentInput, כולל 0 שמור כש-vital אחר היה קיים ו-layout-shift לא נתמך. INP היה אחוזון של כל רשומת event עם interactionId, כך שאינטראקציה אחת יכלה לתרום כמה משכי זמן.

החל מ-2026-11-13, CLS הוא חלון הסשן הגדול ביותר, והמפתח מושמט כש-layout-shift לא נתמך. INP הוא האינטראקציה הגרועה ביותר אחרי קיבוץ לפי interactionId, תוך התעלמות מהאינטראקציה הגבוהה ביותר אחת לכל 50. cwv_fcp, cwv_ttfb ושלושת מפתחות ה-target מתחילים בתאריך הזה.

חלון שחוצה את 2026-11-13 מערבב את שתי ההגדרות. n יכול להיות שונה בין מדדים סביב התאריך הזה.