Web 指标
托管版 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 合并进同一 session、同一 path 最新的 page_view。后一次 flush 覆盖这些键。随 vitals 发送的 path 是该页开始时捕获的 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。页面在 first paint 之前处于 hidden 时省略。 |
| INP | cwv_inp |
ms,整数 | Interaction to Next Paint。event 条目按 interactionId 分组。每次交互取最大 duration。INP 是每 50 次交互忽略一次最高值之后最差的那次交互。 |
| CLS | cwv_cls |
无单位,3 位小数 | Cumulative Layout Shift。最大 session window:间隔小于 1 秒,窗口最长 5 秒,排除带 hadRecentInput 的 shift。 |
| FCP | cwv_fcp |
ms,整数 | First Contentful Paint。页面在 first paint 之前处于 hidden 时省略。 |
| TTFB | cwv_ttfb |
ms,整数 | Time to First Byte。导航的 responseStart - max(activationStart, 0),从 navigation start 起算。 |
经过 prerender 的页面不会被跟踪。
Core Web Vitals 是 LCP、INP 和 CLS。FCP 和 TTFB 是这次读取里的另外两个指标。定义和阈值遵循 Web Vitals。
值 <= good_max 为 good,> poor_min 为 poor,否则为 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。当 LCP、INP、CLS 的 p75 都是 good 时为 true。INP 的 n 为 0 时,只根据 LCP 和 CLS 判断。LCP 的 n 为 0 或 CLS 的 n 为 0 时,cwv_pass 为 null。
CLS 和 INP 只在 Chromium 中采集。其他浏览器上该键不存在。不会存成 0。
浏览器报告了对应条目时才写入 LCP、FCP 和 TTFB。浏览器不报告该条目时省略该键。省略的键不是 0。
n 和 skipped
Section titled “n 和 skipped”n 是该分组里包含该指标的 page_view 行数。skipped 是该分组里不包含该指标的 page_view 行数。
缺失的 vital 计入 skipped,不是 0。路由切换后的浏览可能没有 LCP 和 FCP。非 Chromium 浏览器没有 CLS 和 INP。没有交互的页面没有 INP。这次读取没有最小 n。
Attribution
Section titled “Attribution”vitals 开关打开时,跟踪器可以发送三个 target 属性:
| Property | Selector |
|---|---|
cwv_lcp_target |
LCP 元素 |
cwv_inp_target |
INP 交互目标 |
cwv_cls_target |
CLS 最大 shift 目标 |
每个值都是 CSS selector,会 trim,最长 200 个字符。这些字段只包含 selector:没有文本内容,也没有 URL。
top_poor_targets 列出该指标被评为 poor 的加载里,按 count 取最多 5 个 selector。每项是 { target, count }。FCP 和 TTFB 没有 target 字段,所以 top_poor_targets 是 []。
POST /vitals 和 GET /vitals
Section titled “POST /vitals 和 GET /vitals”Pro。免费账户收到 403,error 为 PRO_REQUIRED。该 403 不计为读取。一次成功响应计为一次计量读取。403 的响应体是标准错误对象:error、message,以及调用方可以看到账单时的 payment。
POST /vitals 的 JSON body,或 GET /vitals 上同名的 query 参数:
| 字段 | 必填 | 取值 |
|---|---|---|
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:按 n 取前 limit 个 path,按最差的 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": [] } } } ]}n 为 0 时 p75 和 rating 为 null。rating 为 good、needs-improvement、poor 或 null。
托管 MCP 工具是 web_vitals。参数与 /vitals 相同:project、days、date_from、date_to、group_by、limit。工具描述包含阈值。p75 是标题数字。文本结果按每个指标打印带单位的 p75、评级、good / needs-improvement / poor 份额,以及 n。
query 和 compare 仍然接受 cwv_* 作为数值属性。在托管版上,事件是 page_view。
vitals 在 @agent-analytics/cli@0.5.41。它调用托管的 /vitals 读取。
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
Section titled “2026-11-13 的 CLS 和 INP”2026-11-13,CLS 和 INP 原地更改(tracker 0.2.5)。
该日期之前,CLS 是不含 hadRecentInput 的 layout-shift 值之和;当已有其他 vital 且不支持 layout-shift 时会存成 0。INP 是每个带 interactionId 的 event 条目的百分位,因此一次交互可能贡献多个 duration。
从 2026-11-13 起,CLS 是最大 session window,不支持 layout-shift 时省略该键。INP 是按 interactionId 分组后、每 50 次忽略一次最高交互的最差交互。cwv_fcp、cwv_ttfb 和三个 target 键从这一天开始。
跨越 2026-11-13 的窗口会混合两种定义。各指标的 n 在该日期两侧可以不同。
