{"_id":"webperf-snippets","_rev":"8-8d2e00f77eab12a09ec1d0df686afff9","name":"webperf-snippets","dist-tags":{"latest":"1.1.0"},"versions":{"0.1.0":{"name":"webperf-snippets","version":"0.1.0","keywords":["webperf","performance","core-web-vitals","lcp","cls","inp","playwright","cli","ci"],"author":{"name":"Joan Leon | @nucliweb"},"license":"MIT","_id":"webperf-snippets@0.1.0","maintainers":[{"name":"nucliweb","email":"joan.leon@gmail.com"}],"homepage":"https://webperf-snippets.nucliweb.net","bugs":{"url":"https://github.com/nucliweb/webperf-snippets/issues"},"bin":{"webperf-snippets":"src/bin.js"},"dist":{"shasum":"bf0b3d9b0ebd2bd102233df23ffcb1f776ba5bcc","tarball":"https://registry.npmjs.org/webperf-snippets/-/webperf-snippets-0.1.0.tgz","fileCount":67,"integrity":"sha512-y+MtsoaIDtdP98WeY7tMXY4b/HwSTMdlq1iUKQR5xQhbIUoUJ5mdZEHepucFCa+zcPOt1dkoekOgysPm4NEdGA==","signatures":[{"sig":"MEUCIGkLxvHeQCvNckJ51BKUqFrjKyQ70NfQsnAjbYLIhiFNAiEA3CYXRwVsYp8WuPsIGuCHfe9VnFr3RqRJtnN12E0k/eE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":568919},"type":"module","engines":{"node":">=20.12.0"},"gitHead":"2371ecf008c0beae8319d4302725e5b89512ee78","scripts":{"test":"vitest run","test:e2e":"vitest run tests/e2e","test:unit":"vitest run tests/unit","test:watch":"vitest"},"_npmUser":{"name":"nucliweb","email":"joan.leon@gmail.com"},"repository":{"url":"git+https://github.com/nucliweb/webperf-snippets.git","type":"git","directory":"cli"},"_npmVersion":"10.9.7","description":"Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.","directories":{},"_nodeVersion":"22.22.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.0.0"},"peerDependencies":{"playwright":">=1.40.0"},"peerDependenciesMeta":{"playwright":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/webperf-snippets_0.1.0_1777919910371_0.15993748681540465","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"webperf-snippets","version":"0.2.0","keywords":["webperf","performance","core-web-vitals","lcp","cls","inp","playwright","cli","ci"],"author":{"name":"Joan Leon | @nucliweb"},"license":"MIT","_id":"webperf-snippets@0.2.0","maintainers":[{"name":"nucliweb","email":"joan.leon@gmail.com"}],"homepage":"https://webperf-snippets.nucliweb.net","bugs":{"url":"https://github.com/nucliweb/webperf-snippets/issues"},"bin":{"webperf-snippets":"src/bin.js"},"dist":{"shasum":"e42c11c28a35e81fb499f2b5ee0727f3295fd1da","tarball":"https://registry.npmjs.org/webperf-snippets/-/webperf-snippets-0.2.0.tgz","fileCount":70,"integrity":"sha512-3Tw1fjKrOab6QfLuQEFJLaecZSHBll7oE4ExHidcbmnRqw8oNwLXdKccRyU6v35KHf3P0xIFusBZUN6bnT+ALQ==","signatures":[{"sig":"MEYCIQDFOaoQRpZ0LszOlvcziCPZYopuHdXFEWs5vrHHQk1rdQIhAKM03Rs4Ou1o2LB0GIw1uLFugi/i4K4TTlD6CJXtArZc","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":577245},"type":"module","engines":{"node":">=20.12.0"},"gitHead":"f4e31a4691134bbd72f4eecab983110d9a39fb50","scripts":{"test":"vitest run","test:e2e":"vitest run tests/e2e","test:unit":"vitest run tests/unit","test:watch":"vitest"},"_npmUser":{"name":"nucliweb","email":"joan.leon@gmail.com"},"repository":{"url":"git+https://github.com/nucliweb/webperf-snippets.git","type":"git","directory":"cli"},"_npmVersion":"10.9.7","description":"Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.","directories":{},"_nodeVersion":"22.22.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.0.0"},"peerDependencies":{"playwright":">=1.40.0"},"peerDependenciesMeta":{"playwright":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/webperf-snippets_0.2.0_1778082346117_0.5299969127406412","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"webperf-snippets","version":"0.3.0","keywords":["webperf","performance","core-web-vitals","lcp","cls","inp","playwright","cli","ci"],"author":{"name":"Joan Leon | @nucliweb"},"license":"MIT","_id":"webperf-snippets@0.3.0","maintainers":[{"name":"nucliweb","email":"joan.leon@gmail.com"}],"homepage":"https://webperf-snippets.nucliweb.net","bugs":{"url":"https://github.com/nucliweb/webperf-snippets/issues"},"bin":{"webperf-snippets":"src/bin.js"},"dist":{"shasum":"f956d5ba654bdfd5fcc6f92d3427abcbbbf71eba","tarball":"https://registry.npmjs.org/webperf-snippets/-/webperf-snippets-0.3.0.tgz","fileCount":81,"integrity":"sha512-5Q27ljT5LxQ6XFYlMpYExwZSZ8ROcfNA8cb4z01BBs6normMIzqScAoGaK5pjjUUgF8EDqU0J5aO9dER5DVIpw==","signatures":[{"sig":"MEQCIEP787Fvp6GLKnruhP6vor0klHZ/1vFonQ+8VPvUs79TAiBqQPty1lN4g8/BbOId0ySIjy8qVNl6Wt9yfJEKlZGxbA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDQeOmhiSrPHVlnvvY/7razO9ZAlCiaerl0lJ6NN64lLgIhAOWmtQ2FoS3GtI4qd+rlJDlEoWLTa1g9rfjQJRWFKWEy","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":732053},"type":"module","engines":{"node":">=20.12.0"},"gitHead":"a8588e7281452522e436b8dae94bdacf8a2c215f","scripts":{"test":"vitest run","test:e2e":"vitest run tests/e2e","test:unit":"vitest run tests/unit","test:watch":"vitest"},"_npmUser":{"name":"nucliweb","email":"joan.leon@gmail.com"},"repository":{"url":"git+https://github.com/nucliweb/webperf-snippets.git","type":"git","directory":"cli"},"_npmVersion":"10.9.9","description":"Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.","directories":{},"_nodeVersion":"22.23.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.0.0"},"peerDependencies":{"playwright":">=1.40.0"},"peerDependenciesMeta":{"playwright":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/webperf-snippets_0.3.0_1790956584889_0.9482136660497558","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"webperf-snippets","version":"0.4.0","keywords":["webperf","performance","core-web-vitals","lcp","cls","inp","playwright","cli","ci"],"author":{"name":"Joan Leon | @nucliweb"},"license":"MIT","_id":"webperf-snippets@0.4.0","maintainers":[{"name":"nucliweb","email":"joan.leon@gmail.com"}],"homepage":"https://webperf-snippets.nucliweb.net","bugs":{"url":"https://github.com/nucliweb/webperf-snippets/issues"},"bin":{"webperf-snippets":"src/bin.js"},"dist":{"shasum":"745368dc46aa1d1cf649f812f34c5ce661fe61a9","tarball":"https://registry.npmjs.org/webperf-snippets/-/webperf-snippets-0.4.0.tgz","fileCount":84,"integrity":"sha512-Jbx88RzbI1FTshhaEH3snIQ9Y35FyC7bmGPXkM9qhCJ5BxBmqjkfuSWQDJHLQiXqkO2m4tadF2XJq0Qz0KhvaA==","signatures":[{"sig":"MEYCIQDo1SWqheH5Ry0qDogKOL10iaOcNn8py1SqO+unp84iZwIhAOMx6QFjVEpRYAFc9iyZwHaEr0ZNwsyqegSE+xe2pXJO","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIEzXkSC8cposdItqYSvVzLvzSOA7Ukg1Xvumx8YexQoCAiARyLH8Et7uUNCCAQe979TzkIvAZDOjvE0XT3ayOBk3ag==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":761877},"type":"module","engines":{"node":">=20.12.0"},"gitHead":"88da12eeb33ee9449a666113705d2e0e080e1bce","scripts":{"test":"vitest run","test:e2e":"vitest run tests/e2e","test:unit":"vitest run tests/unit","test:watch":"vitest"},"_npmUser":{"name":"nucliweb","email":"joan.leon@gmail.com"},"repository":{"url":"git+https://github.com/nucliweb/webperf-snippets.git","type":"git","directory":"cli"},"_npmVersion":"10.9.9","description":"Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.","directories":{},"_nodeVersion":"22.23.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.0.0"},"peerDependencies":{"playwright":">=1.40.0"},"peerDependenciesMeta":{"playwright":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/webperf-snippets_0.4.0_1791070418408_0.11727522524179657","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"webperf-snippets","version":"0.4.1","keywords":["webperf","performance","core-web-vitals","lcp","cls","inp","playwright","cli","ci"],"author":{"name":"Joan Leon | @nucliweb"},"license":"MIT","_id":"webperf-snippets@0.4.1","maintainers":[{"name":"nucliweb","email":"joan.leon@gmail.com"}],"homepage":"https://webperf-snippets.nucliweb.net","bugs":{"url":"https://github.com/nucliweb/webperf-snippets/issues"},"bin":{"webperf-snippets":"src/bin.js"},"dist":{"shasum":"27a9dd4ace6d6af6a562588287fdb492e2691104","tarball":"https://registry.npmjs.org/webperf-snippets/-/webperf-snippets-0.4.1.tgz","fileCount":84,"integrity":"sha512-SjFlTfekLVwVM+riwY5ALN+L5NW/ybG35zSnWhFz80OoHlxliW381Jpv+CEhy/EhAF29VozS7UJhbeKbY6WkTg==","signatures":[{"sig":"MEUCIEiaSgpEEATMTufIrY7I8H3bPDsSYigPpLlW7jnAXpSrAiEAo+WqlOxeo2Z0ZXebYZd86+0tGUT10yvg3nGpyc854gs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCoV02s8K3oFHX4j+JCy7fo+yeCSLuzR4AaGlsNJjjMtwIhAMPcZJR4zzr5RdBShCZN9NYCyTazrhwMkAv3SeMAkRHN","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":763363},"type":"module","engines":{"node":">=20.12.0"},"gitHead":"b7bbdd99021c456d05c9d0689762ba03a5c207da","scripts":{"test":"vitest run","test:e2e":"vitest run tests/e2e","test:unit":"vitest run tests/unit","test:watch":"vitest"},"_npmUser":{"name":"nucliweb","email":"joan.leon@gmail.com"},"repository":{"url":"git+https://github.com/nucliweb/webperf-snippets.git","type":"git","directory":"cli"},"_npmVersion":"10.9.9","description":"Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.","directories":{},"_nodeVersion":"22.23.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^2.0.0"},"peerDependencies":{"playwright":">=1.40.0"},"peerDependenciesMeta":{"playwright":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/webperf-snippets_0.4.1_1791117805774_0.5938786443701696","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"webperf-snippets","version":"0.5.0","keywords":["webperf","performance","core-web-vitals","lcp","cls","inp","playwright","cli","ci"],"author":{"name":"Joan Leon | @nucliweb"},"license":"MIT","_id":"webperf-snippets@0.5.0","maintainers":[{"name":"nucliweb","email":"joan.leon@gmail.com"}],"homepage":"https://webperf-snippets.net","bugs":{"url":"https://github.com/nucliweb/webperf-snippets/issues"},"bin":{"webperf-snippets":"src/bin.js"},"dist":{"shasum":"574200a47063b4ce45a0be0492e7008f601d72be","tarball":"https://registry.npmjs.org/webperf-snippets/-/webperf-snippets-0.5.0.tgz","fileCount":84,"integrity":"sha512-8Bav1a8MAxutNMpCO98Yj6G/J6+O2yqc0NJKU2KdNHYS78ICpkl68AuSopSwQrYp4FufYA5dRDa9q1AvfM9cPw==","signatures":[{"sig":"MEUCIEXtJgO0DKhbe/ilkesphpB5L5py2KUC2+rzV3UCiL1YAiEAtR/sRHfSBdg9yS1/P48DDGRx/w2FMtMMRDCG7uai4sY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIAr8prw84eM/OzQsQi5bzUJmZa0KR9pM1F5bbBs/hsfoAiEAnDaiLn5cNjnCCmL+bpt/AQK1bRJF4rdMNW/hDAzktas=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":775473},"type":"module","engines":{"node":">=20.12.0"},"gitHead":"2c2e961a8314f0974e1623e85e55a051a5b5b770","scripts":{"test":"vitest run","test:e2e":"vitest run tests/e2e","test:unit":"vitest run tests/unit","test:watch":"vitest"},"_npmUser":{"name":"nucliweb","email":"joan.leon@gmail.com"},"repository":{"url":"git+https://github.com/nucliweb/webperf-snippets.git","type":"git","directory":"cli"},"_npmVersion":"10.9.9","description":"Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.","directories":{},"_nodeVersion":"22.23.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.11"},"peerDependencies":{"playwright":">=1.40.0"},"peerDependenciesMeta":{"playwright":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/webperf-snippets_0.5.0_1792018392645_0.6218226535557037","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"webperf-snippets","version":"1.0.0","keywords":["webperf","performance","core-web-vitals","lcp","cls","inp","playwright","cli","ci"],"author":{"name":"Joan Leon | @nucliweb"},"license":"MIT","_id":"webperf-snippets@1.0.0","maintainers":[{"name":"nucliweb","email":"joan.leon@gmail.com"}],"homepage":"https://webperf-snippets.net","bugs":{"url":"https://github.com/nucliweb/webperf-snippets/issues"},"bin":{"webperf-snippets":"src/bin.js"},"dist":{"shasum":"6a751d62fbab9080aa6ca7d0ec08ed32332bdb36","tarball":"https://registry.npmjs.org/webperf-snippets/-/webperf-snippets-1.0.0.tgz","fileCount":84,"integrity":"sha512-GqTMOrcHXe4vxIyfJYx4xj8hiBogoubZu+FuXiX0ySgNJfY6RazhQAmv0XkJeva+hpXvrZeeZu2MbGjXHqrZxQ==","signatures":[{"sig":"MEYCIQD92lcv9xN+xwWTdvLYBktcWcpNHK5Hu+ZhjpKlceHzLQIhAJYdCMxOiQh5SoGvminovnh1hqQc9oNTqt0rlhj385UD","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIEWlFpCAdzjkGAT7yEEalyoCQ6dlmPo0UUpsCDKiFZvBAiB91hL0PbiV4cz20LzWX3g4yHjDDHCsE66jklD7o2smxw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":775473},"type":"module","engines":{"node":">=20.12.0"},"gitHead":"f48c30a183ac1479814f211013f8fff69f45888d","scripts":{"test":"vitest run","test:e2e":"vitest run tests/e2e","test:unit":"vitest run tests/unit","test:watch":"vitest"},"_npmUser":{"name":"nucliweb","email":"joan.leon@gmail.com"},"repository":{"url":"git+https://github.com/nucliweb/webperf-snippets.git","type":"git","directory":"cli"},"_npmVersion":"10.9.9","description":"Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.","directories":{},"_nodeVersion":"22.23.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^4.1.11"},"peerDependencies":{"playwright":">=1.40.0"},"peerDependenciesMeta":{"playwright":{"optional":false}},"_npmOperationalInternal":{"tmp":"tmp/webperf-snippets_1.0.0_1792104156558_0.21327087471567574","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"_id":"webperf-snippets@1.1.0","bin":{"webperf-snippets":"src/bin.js"},"bugs":{"url":"https://github.com/nucliweb/webperf-snippets/issues"},"dist":{"shasum":"dc95c2e929c0b23c4799b1c7b3dfe984a6fd79df","tarball":"https://registry.npmjs.org/webperf-snippets/-/webperf-snippets-1.1.0.tgz","fileCount":91,"integrity":"sha512-Qp43pq/myC76VQmqp5XSGUCL7zEwlWZ0/0FM6zrFxzdc+SkRLKFkzvVuV9gy7H5d5AKEYbRaMkbFGab0wySD+g==","signatures":[{"sig":"MEYCIQCLS5/8ZK6Qf1o33H/U5J37/xoAbFyVUirKvCbhrpsVaAIhAMz/s32dxq+jnUAQrZ72o9T1bsR6/ytGpXc165p27xyn","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGtjqblV55fy6rkek0EyFMX6WV47PD88/IXeTiXeDEN9AiBtirj/g6xalARr6FEemnT7jcLPlwQ+hQWJ6bCBQ8LPYg=="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/webperf-snippets@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":842878},"name":"webperf-snippets","type":"module","author":{"name":"Joan Leon | @nucliweb"},"engines":{"node":">=20.12.0"},"gitHead":"408e701a29c70caccaf0a970e813723f6bfd17c3","license":"MIT","mcpName":"io.github.nucliweb/webperf-snippets","scripts":{"test":"vitest run","test:e2e":"vitest run tests/e2e","test:unit":"vitest run tests/unit","test:watch":"vitest"},"version":"1.1.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"a0ecebc5-50ee-43c5-bebe-3baba7f1ba54"}},"homepage":"https://webperf-snippets.net","keywords":["webperf","performance","core-web-vitals","lcp","cls","inp","playwright","cli","ci"],"repository":{"url":"git+https://github.com/nucliweb/webperf-snippets.git","type":"git","directory":"cli"},"_npmVersion":"11.21.1","description":"Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.","directories":{},"maintainers":[{"name":"nucliweb","email":"joan.leon@gmail.com"}],"_nodeVersion":"24.21.0","dependencies":{"@modelcontextprotocol/server":"^2.3.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"^5.0.5","@modelcontextprotocol/client":"^2.3.1"},"peerDependencies":{"playwright":">=1.40.0"},"peerDependenciesMeta":{"playwright":{"optional":false}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/webperf-snippets_1.1.0_1792588596131_0.1949534712498895"}}},"time":{"created":"2026-05-04T18:38:30.265Z","modified":"2026-10-21T13:16:36.720Z","0.1.0":"2026-05-04T18:38:30.542Z","0.2.0":"2026-05-06T15:45:46.314Z","0.3.0":"2026-10-02T15:56:24.985Z","0.4.0":"2026-10-03T23:33:38.502Z","0.4.1":"2026-10-04T12:43:25.880Z","0.5.0":"2026-10-14T22:53:12.722Z","1.0.0":"2026-10-15T22:42:36.679Z","1.1.0":"2026-10-21T13:16:36.254Z"},"bugs":{"url":"https://github.com/nucliweb/webperf-snippets/issues"},"author":{"name":"Joan Leon | @nucliweb"},"license":"MIT","homepage":"https://webperf-snippets.net","keywords":["webperf","performance","core-web-vitals","lcp","cls","inp","playwright","cli","ci"],"repository":{"url":"git+https://github.com/nucliweb/webperf-snippets.git","type":"git","directory":"cli"},"description":"Run curated WebPerf Snippets headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes.","maintainers":[{"name":"nucliweb","email":"joan.leon@gmail.com"}],"readme":"# webperf-snippets CLI\n\nRun curated [WebPerf Snippets](https://webperf-snippets.net) headlessly via Playwright. Diagnose Core Web Vitals beyond what Lighthouse exposes and gate CI on real performance budgets.\n\n<img width=\"1820\" height=\"1442\" alt=\"webperf-snippets-CLI\" src=\"https://github.com/user-attachments/assets/af7e6b02-8877-407e-87a4-db063468b5fb\" />\n\n\n> **Status:** v0.4. Core Web Vitals, loading, interaction and structural audit workflows, and every snippet of the collection by name. See the [Roadmap](#roadmap).\n\n## Why\n\nLighthouse gives you a score. The DevTools snippets give you the *diagnosis*, such as TTFB / Resource Load Delay / Element Render Delay sub-parts, LoAF script attribution, and render-blocking resources. This CLI runs the same curated snippets in a headless browser so you can:\n\n- Diagnose LCP regressions in CI without copy-pasting into DevTools.\n- Gate pull requests on real performance budgets.\n- Automate the snippets you already run by hand.\n\n## Install\n\nPlaywright is a peer dependency. Install both, plus the chromium browser:\n\n```bash\nnpm install --save-dev webperf-snippets playwright\nnpx playwright install chromium\n```\n\n## Usage\n\n```bash\nnpx webperf-snippets <url> [options]\n```\n\n### Examples\n\nRun the default Core Web Vitals workflow (LCP + CLS, plus LCP-Subparts if LCP > 2.5s):\n\n```bash\nnpx webperf-snippets https://example.com\n```\n\nLoading audit (11 steps: TTFB, FCP, render-blocking, scripts, resource timings, third-party impact, fonts, cache; the list is in the [CLI page](https://webperf-snippets.net/CLI)):\n\n```bash\nnpx webperf-snippets https://example.com --workflow loading\n```\n\nStructural checks for CI (22 checks: render-blocking, compression, fonts, images, hints, DOM size and more; the list is in the [CLI page](https://webperf-snippets.net/CLI)):\n\n```bash\nnpx webperf-snippets https://example.com --workflow audit\n```\n\nMarkdown output for PR comments:\n\n```bash\nnpx webperf-snippets https://example.com --markdown\n```\n\nJSON output (for piping into `jq` or CI):\n\n```bash\nnpx webperf-snippets https://example.com --json\n```\n\nSingle snippet:\n\n```bash\nnpx webperf-snippets https://example.com --snippet LCP-Subparts\n```\n\nSynthetic INP measurement with an interaction script:\n\n```bash\nnpx webperf-snippets https://example.com --snippet INP --interact-script interactions.json\nnpx webperf-snippets https://example.com --snippet Interaction/Interactions --interact-script interactions.json\n```\n\nThe Interaction snippets (`Interactions`, `Input-Latency-Breakdown`, `LongTask`, `Forced-Synchronous-Layout`...) are installed before the first step and read after the last one, so their result holds what the steps caused.\n\nThe CLI waits for the browser to report the timing of the last interaction before it reads the snippets. A script that ends right after a click still reads the page before anything the click sets in motion later has happened, such as a request or an animation, so end it with a `wait` step when you want to measure that.\n\nInteraction audit (long tasks, long animation frames, scroll, layout shifts, forced layouts, interaction latency). It scrolls the page, or runs your `--interact-script`; the steps that need a click are skipped when the script has none:\n\n```bash\nnpx webperf-snippets https://example.com --workflow interaction\n```\n\nPages behind a login, with a Playwright storage state (cookies and localStorage):\n\n```bash\n# Step 1: sign in once and save the session\nnpx playwright codegen --save-storage=auth.json https://example.com/login\n\n# Step 2: measure an authenticated page\nnpx webperf-snippets https://example.com/dashboard --storage-state auth.json\n```\n\nThe file holds live session cookies. Keep it out of version control (add it to `.gitignore`) and use a throwaway account when you run it in CI. The CLI exits with code `2` if the path does not exist.\n\nCompare the measured values with CrUX field data (what real users experience at the 75th percentile):\n\n```bash\nCRUX_API_KEY=your-key npx webperf-snippets https://example.com\n```\n\n```\nField data (CrUX p75, mobile)\n  🟡 LCP    2.80s      needs-improvement    (synthetic: 2.10s)\n  🟢 CLS    0.0800     good                 (synthetic: 0.0500)\n  🟡 INP    220ms      needs-improvement    (synthetic: n/a)\n```\n\nGet a key for the [Chrome UX Report API](https://developer.chrome.com/docs/crux/api) and pass it with `--crux-key` or the `CRUX_API_KEY` environment variable; prefer the variable, because a flag ends up in shell history and CI logs. The section appears in the human and markdown output and under `crux` in the `--json` output.\n\n- The population follows `--viewport`: `desktop` uses desktop data, `mobile` and `tablet` use phone data. The heading says which one.\n- When the page itself has no data, the CLI looks the origin up instead and labels the section `origin-level`, so it is not mistaken for page-level data. If the origin has none either, the output says `Field data: not available`.\n- A CrUX error (quota, network, no answer within 10 seconds) only skips the section. It never changes the exit code, and the key is never printed.\n- INP shows `n/a` as the synthetic value unless you run an interaction script.\n\nSend the results to an endpoint after the run with `--report-to`:\n\n```bash\nnpx webperf-snippets https://example.com --workflow audit \\\n  --report-to https://reports.example.com/api/report \\\n  --api-key $REPORT_API_KEY\n```\n\nWithout `--report-to` the CLI makes no external calls. With it, the results are POSTed as JSON once the snippets have finished:\n\n```json\n{\n  \"url\": \"https://example.com\",\n  \"workflow\": \"audit\",\n  \"timestamp\": \"2026-05-06T10:00:00.000Z\",\n  \"navMs\": 1240,\n  \"results\": [],\n  \"meta\": { \"viewport\": \"mobile\", \"waitMs\": 3000, \"cli_version\": \"1.1.0\" }\n}\n```\n\nFor a `--snippet` run, `workflow` is `null` and a `snippet` field carries the name. `results` is the same list the `--json` output contains, so it can include URLs and details of the measured page; send it only to an endpoint you trust.\n\n- The URL must be `https`. `http` is accepted only for `localhost`, so a key is never sent in clear text.\n- `--api-key` is sent as `Authorization: Bearer <key>`. Prefer the `PERF_REVIEWS_API_KEY` environment variable, because a flag ends up in shell history and CI logs. The key is never printed.\n- The exit code never depends on the report. A failed POST (error status, unreachable endpoint, or no answer within 5 seconds) prints a warning and the exit code stays the one the budgets and snippets decide. If the endpoint answers `{ \"ok\": false, \"regressions\": [...] }`, the regressions are printed as a warning, again without changing the exit code.\n\nCI gating:\n\n```bash\nnpx webperf-snippets https://example.com --budget-lcp 2500 --budget-cls 0.1\n```\n\n### Options\n\n| Option                       | Description                                                            |\n| ---------------------------- | ---------------------------------------------------------------------- |\n| `--workflow <name>`          | Workflow to run. Default: `core-web-vitals`. Options: `core-web-vitals`, `loading`, `audit`, `interaction`. |\n| `--snippet <name>`           | Run a single snippet by name, alias or `Category/Name` path.           |\n| `--json`                     | Output JSON instead of formatted text.                                 |\n| `--markdown`                 | Output GitHub-renderable markdown (for PR comments).                   |\n| `--viewport <preset>`        | Viewport preset: `mobile` (default), `tablet`, `desktop`.             |\n| `--wait <ms>`                | Post-load wait before evaluating snippets. Default: `3000`.            |\n| `--interact-script <path>`   | JSON file with interactions to run after the page loads (`scroll`, `click`, `hover`, `type`, `wait`). The Interaction snippets are installed first and read afterwards. |\n| `--storage-state <path>`     | Playwright storage state (cookies and localStorage) for pages that require authentication. |\n| `--crux-key <key>`           | Add CrUX field data (p75) next to the measured values. Prefer `CRUX_API_KEY`. |\n| `--report-to <url>`          | POST the results to this `https` URL after the run. No external calls without it. |\n| `--api-key <key>`            | Sent as a Bearer token with `--report-to`. Prefer `PERF_REVIEWS_API_KEY`. |\n| `--budget-lcp <ms>`          | Exit `1` if LCP exceeds this value.                                    |\n| `--budget-cls <score>`       | Exit `1` if CLS exceeds this value.                                    |\n| `--verbose`                  | Show all items, including passing checks.                              |\n| `--headed`                   | Show the browser window (debug).                                       |\n| `-h, --help`                 | Show help.                                                             |\n\n### Snippet aliases\n\n| Alias              | Snippet                                        |\n| ------------------ | ---------------------------------------------- |\n| `LCP`              | CoreWebVitals/LCP                              |\n| `CLS`              | CoreWebVitals/CLS                              |\n| `INP`              | CoreWebVitals/INP                              |\n| `LCP-Subparts`     | CoreWebVitals/LCP-Subparts                     |\n| `fonts`            | Loading/Fonts-Preloaded-Loaded-and-used-above-the-fold |\n| `render-blocking`  | Loading/Find-render-blocking-resources         |\n| `resource-hints`   | Loading/Resource-Hints-Validation              |\n| `preload-scripts`  | Loading/Validate-Preload-Async-Defer-Scripts   |\n| `priority-hints`   | Loading/Priority-Hints-Audit                   |\n| `critical-css`     | Loading/Critical-CSS-Detection                 |\n| `ttfb`             | Loading/TTFB-Sub-Parts                         |\n| `script-parties`   | Loading/First-And-Third-Party-Script-Info      |\n| `script-loading`   | Loading/Script-Loading                         |\n| `lazy-atf`         | Loading/Find-Above-The-Fold-Lazy-Loaded-Images |\n| `lazy-conflict`    | Loading/Find-Images-With-Lazy-and-Fetchpriority |\n| `eager-below-fold` | Loading/Find-non-Lazy-Loaded-Images-outside-of-the-viewport |\n\n### Follow-up steps\n\nThe results of a run can add steps on the same page load: LCP over 2.5 s adds `LCP-Subparts`, over 4 s `LCP-Trail`; an image or video LCP adds its entropy, image or video audit; CLS over 0.1 adds `Layout-Shift-Loading-and-Interaction`, over 0.25 also the lazy images, fonts, critical CSS and images without dimensions; TTFB over 600 ms adds `TTFB-Sub-Parts`; FCP over 1.8 s adds the render-blocking check. The full table is in the [CLI page](https://webperf-snippets.net/CLI). Each snippet runs once, and a follow-up informs: its `error` issues do not change the exit code.\n\n### Exit codes\n\n| Code | Meaning                                       |\n| ---- | --------------------------------------------- |\n| `0`  | All checks passed.                            |\n| `1`  | Budget violation, a snippet errored, or a step of the workflow reported an `error` issue. |\n| `2`  | Usage error (missing URL, unknown workflow).  |\n\n## MCP server\n\n`webperf-snippets mcp` starts a [Model Context Protocol](https://modelcontextprotocol.io) server over stdio, so an AI agent can call the snippets by name instead of reading their source. Add it to a client that launches local servers, for example Claude Code:\n\n```bash\nclaude mcp add webperf -- npx -y webperf-snippets mcp\n```\n\n| Tool            | What it does                                                                 |\n| --------------- | ---------------------------------------------------------------------------- |\n| `list_snippets` | Lists the snippets with their category, title, short aliases and whether they track interactions. Takes an optional `category`. |\n| `run_snippet`   | Opens a URL in a headless Chromium, runs one snippet and returns the object it returns. Takes `url`, `snippet` (name, alias or `Category/Name`), and optional `viewport` and `waitMs`. The snippets that record interactions run on a page opened with `open_page`. |\n| `run_workflow`  | Runs a workflow of the CLI (`core-web-vitals`, `audit`, `loading`, `interaction`) and the follow-ups of its decision tree. Takes `url`, `workflow`, and optional `viewport` and `waitMs`. |\n| `get_crux`      | Returns the CrUX p75 of LCP, CLS and INP for a URL, or its origin. Takes `url` and an optional `formFactor` (`phone`, `desktop`, `tablet`). Needs `CRUX_API_KEY` in the environment of the server. |\n| `open_page`     | Opens a URL in a page that stays open between calls and installs tracking snippets (`track`, such as `INP`). Returns a `sessionId`. |\n| `interact`      | Runs steps on an open page: `click`, `type`, `hover`, `scroll` or `wait`. |\n| `read_results`  | Returns what the tracking snippets of an open page have recorded. |\n| `close_page`    | Closes an open page. |\n\nThe server also offers resources, documents a client can attach to the context:\n\n| Resource                         | What it has                                                              |\n| -------------------------------- | ------------------------------------------------------------------------ |\n| `webperf://schema`               | The contract every snippet result follows: base shape, statuses, how to read a result. |\n| `webperf://schema/{snippet}`     | The fields one snippet returns, with an example.                         |\n| `webperf://workflows/{category}` | The workflows and the decision tree of a category.                       |\n\nAnd prompts, templates that chain the tools (in Claude Code, `/mcp__webperf__audit_lcp`): `audit_lcp`, `debug_inp` and `audit_page`, each with a `url` argument.\n\nThe CrUX key goes in the configuration of the client, never in a tool argument:\n\n```bash\nclaude mcp add webperf -e CRUX_API_KEY=<key> -- npx -y webperf-snippets mcp\n```\n\nAt most three pages are open at a time, a page closes after 10 minutes without use, and every page and Chromium close when the client disconnects.\n\nThe server answers clients of both eras of the protocol: the 2026-07-28 revision and the earlier ones that open with `initialize`. [ADR 0002](../docs/adr/0002-mcp-server-as-cli-subcommand.md) explains why it is a subcommand and uses stdio.\n\n## CI example\n\nGitHub Actions, fail the PR if LCP exceeds 2.5s:\n\n```yaml\n- run: |\n    npm install --no-save webperf-snippets playwright\n    npx playwright install --with-deps chromium\n    npx webperf-snippets https://staging.example.com --budget-lcp 2500 --budget-cls 0.1\n```\n\n### GitHub Action\n\nThe repository ships a composite action that installs the CLI and Chromium, runs a workflow and exposes the result as markdown, so any repository can gate on performance budgets without extra setup:\n\n```yaml\njobs:\n  webperf:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - uses: nucliweb/webperf-snippets/.github/actions/webperf-snippets@main\n        id: webperf\n        with:\n          url: https://staging.example.com\n          budget-lcp: 2500\n          fail-on-budget: \"false\"\n\n      - uses: actions/github-script@v7\n        env:\n          BODY: ${{ steps.webperf.outputs.markdown }}\n        with:\n          script: |\n            await github.rest.issues.createComment({\n              ...context.repo,\n              issue_number: context.issue.number,\n              body: process.env.BODY,\n            });\n\n      - if: steps.webperf.outputs.exit-code != '0'\n        run: exit 1\n```\n\n| Input            | Default             | Description                                                                                  |\n| ---------------- | ------------------- | -------------------------------------------------------------------------------------------- |\n| `url`            | required            | URL to measure.                                                                              |\n| `workflow`       | `core-web-vitals`   | Workflow to run: `core-web-vitals`, `loading`, `audit` or `interaction`.                                    |\n| `budget-lcp`     | `2500`              | LCP budget in ms. An empty value disables the check.                                         |\n| `budget-cls`     | `0.1`               | CLS budget. An empty value disables the check.                                               |\n| `fail-on-budget` | `true`              | Fail the step when a budget is exceeded or a snippet errors. Use `\"false\"` to read `exit-code` and decide yourself. |\n| `cli-version`    | `latest`            | Version of the `webperf-snippets` npm package to run.                                        |\n\n| Output      | Description                                                                          |\n| ----------- | ------------------------------------------------------------------------------------ |\n| `markdown`  | The results as markdown. Also written to the job summary.                            |\n| `exit-code` | Exit code of the CLI: `0` passed, `1` budget exceeded or a snippet errored, `2` usage error. |\n\nThe markdown includes text taken from the measured page, so pass it to other steps through an environment variable (`env:` and `process.env`) as above, never by interpolating `${{ steps.webperf.outputs.markdown }}` inside a script. With `fail-on-budget: \"false\"` the action step always succeeds, which lets later steps post the comment before the job fails. Without `permissions: pull-requests: write` the comment step cannot post on a pull request.\n\nLCP, CLS and INP vary by 15 to 30% on shared runners; prefer the deterministic `audit` workflow for a gate, or generous budgets.\n\n## Publishing\n\nThe CLI package is published to npm via a tag-based workflow. Publishing is explicit and intentional; it only happens when a `cli-v*` tag is pushed.\n\n### Release steps\n\n1. Bump the version in `cli/package.json`.\n2. Commit the version change.\n3. Tag and push:\n   ```bash\n   git tag cli-v0.2.0\n   git push origin cli-v0.2.0\n   ```\n4. The `publish-cli` CI job runs, executes the full test suite, and publishes to npm.\n\n### Why tag-based and not path-based\n\nAn alternative is to publish automatically on every push to `main` that touches `cli/`, using a version check to skip republishes. Tag-based publishing was chosen instead because it keeps releases deliberate; a passing CI on `main` does not mean the package is ready to ship, and a tag communicates that intent explicitly.\n\n### Access control\n\nTag protection rules restrict who can push `cli-v*` tags. Configure them under **Settings → Rules → New ruleset** in the repository, targeting the `cli-v*` tag pattern and limiting push access to admins or maintainers. This ensures only authorized collaborators can trigger a publish.\n\n### Required secret\n\nThe `NPM_TOKEN` secret must be set in the repository settings with publish access to the `webperf-snippets` npm package.\n\n## Known limitations\n\n- **CLS in headless is conservative**: layout shifts that only happen on scroll are missed unless you script the scroll.\n- **First navigation only**: each `webperf-snippets` invocation runs one URL. SPAs need the post-route URL passed directly.\n- **Synthetic INP ≠ field INP**: `--interact-script` measures handler latency for a single scripted event. Real INP reflects the worst interaction across all user sessions; use RUM for field data.\n\n## Roadmap\n\n- ~~v0.2: Loading workflow (TTFB, FCP, render-blocking, scripts, fonts), shared page session, synthetic interactions for INP, markdown reporter for PR comments.~~ ✓ Released\n- ~~v0.3: GitHub Action wrapper, auth flows (login + measure logged-in pages), CrUX field-data enrichment, `--report-to`.~~ ✓ Released\n- ~~v0.4: Every snippet by name, a 22-step audit, an 11-step loading workflow, the interaction workflow and decision-tree follow-ups for Core Web Vitals.~~ ✓ Released\n\n## How it works\n\n1. Launches headless chromium via Playwright.\n2. Navigates to the URL, waits for the `load` event and then for `--wait` milliseconds (3000 by default), so late entries reach the page.\n3. Evaluates each snippet's IIFE in the page context, capturing the returned object. The snippets read the entries Chrome only exposes to observers (LCP, layout shifts, long tasks, event timing) with a buffered `PerformanceObserver`, so they see the entries recorded before they ran.\n4. With an interaction script, installs the tracking snippets first, runs the interactions, lets the page settle and then reads the tracking data and runs the other snippets.\n5. Applies the workflow's decision tree to enqueue follow-up snippets.\n6. Renders results (human or JSON) and exits with an appropriate code.\n\n## License\n\nMIT, see [LICENSE](../LICENSE).\n","readmeFilename":"README.md"}