crux-vitals
v2.0.0
Published
Zero-dependency CrUX API client for batch Core Web Vitals analysis — LCP, CLS, INP, FCP, TTFB with history and origin queries
Downloads
111
Maintainers
Keywords
Readme
crux-vitals
Zero-dependency Node.js client for the Chrome User Experience Report (CrUX) API. Batch-analyze Core Web Vitals and real-user field performance data across hundreds of URLs with automatic rate limiting, retries, and CSV/JSON export.
urls.csv ──> [ crux-vitals ] ──> JSON + CSV results
|
| CrUX API
| (batch requests)
v
Google's real-user
performance dataHow it works
You provide crux-vitals does You get
─────────── ────────────────── ──────────────
A list of URLs ---> Batches them (20/req) ---> P75 metrics
Calls CrUX API Benchmark status
Handles rate limits Pass/fail summary
Retries on failure JSON + CSV filesCore Web Vitals (with benchmarks):
| Metric | What it measures | Good | Poor | |--------|-----------------|------|------| | CLS | Visual stability | ≤ 0.1 | > 0.25 | | LCP | Loading speed | ≤ 2.5s | > 4.0s | | FCP | First paint | ≤ 1.8s | > 3.0s | | INP | Interactivity | ≤ 200ms | > 500ms | | TTFB | Server response | ≤ 800ms | > 1.8s |
Additional metrics (p75, no official thresholds):
| Metric | What it measures | |--------|-----------------| | RTT | Network round-trip time | | LCP_TTFB | LCP image time to first byte | | LCP_LoadDelay | LCP image resource load delay | | LCP_LoadDuration | LCP image resource load duration | | LCP_RenderDelay | LCP image element render delay |
Fraction metrics (distribution breakdowns):
| Metric | Keys | |--------|------| | Navigation types | navigate, navigate_cache, reload, restore, back_forward, back_forward_cache, prerender | | LCP resource type | image, text | | Form factors | phone, desktop, tablet (only when no device filter) |
Installation
npm install crux-vitalsRequires Node.js 20.6+ and a CrUX API key.
Use as a library
import { CrUX } from 'crux-vitals';
const crux = new CrUX('your-api-key');
// Single URL
const result = await crux.query('https://example.com');
// { url, device, CLS, LCP, FCP, INP, TTFB, ... }
// Batch (auto-handles rate limits + batching)
const { results, noData } = await crux.queryAll(urls, {
device: ['PHONE', 'DESKTOP'],
includeHistogram: true,
});
// Origin-level (aggregated across all pages)
const origin = await crux.queryOrigin('https://example.com');
// Historical trends (default 25 periods, max 40)
const trend = await crux.history('https://example.com', { periods: 40 });
// { url, CLS_timeseries: [0.06, 0.08, ...], LCP_timeseries: [...], ... }
// Evaluate any value against benchmarks
CrUX.evaluate('LCP', 2300);
// { p75: 2300, status: 'GOOD', diff: 200 }
CrUX.BENCHMARKS;
// { CLS: { good: 0.1, poor: 0.25 }, LCP: { good: 2500, poor: 4000 }, ... }Constructor options
const crux = new CrUX('key', {
batchSize: 20, // URLs per API request (max 20)
batchDelay: 10000, // ms between batches
concurrency: 1, // parallel batch workers
retries: 3, // retry attempts per request
});CLI usage
# Install globally
npm install -g crux-vitals
# Or use npx
npx crux-vitals --helpGet your free CrUX API key, then create a urls.csv file with a url column:
url
https://example.com/
https://example.com/about/# Pass key as flag
crux-vitals --key YOUR_API_KEY
# Or set as env var
export KEY=YOUR_API_KEY
crux-vitals
# With options
crux-vitals --key YOUR_API_KEY --device PHONE,DESKTOP --histogramCLI options
--file <path> Input CSV (default: urls.csv)
--folder <name> Output folder prefix (default: crux-results)
--device <types> PHONE,DESKTOP,TABLET (default: PHONE)
--key, -k <key> CrUX API key (or set KEY env var)
--origin Origin-level data (instead of per-URL)
--history Trend data (25 periods of historical p75)
--histogram Include % good/NI/poor distribution
--help, -h Show helpOutput
crux-results_2026-03-26/
all-cwv-test.json Full results with all metrics
all-cwv-test.csv Spreadsheet-ready version
urls.csv Copy of your input
no-data-urls.csv URLs without CrUX data (if any)API
new CrUX(apiKey, config?)
Creates a new CrUX instance.
Instance methods
| Method | Description |
|--------|-------------|
| query(url, options?) | Query a single URL |
| queryOrigin(origin, options?) | Query a single origin |
| queryAll(urls, options?) | Batch query multiple URLs |
| history(url, options?) | Get history for a URL |
| historyOrigin(origin, options?) | Get history for an origin |
| historyAll(urls, options?) | Batch history for multiple URLs |
Static
| Property/Method | Description |
|----------------|-------------|
| CrUX.BENCHMARKS | Frozen object with thresholds for CLS, LCP, FCP, INP, TTFB |
| CrUX.evaluate(metric, value) | Evaluate a p75 value against its benchmark |
Requirements
- Node.js 20.6+ (uses native
fetchand--env-file) - CrUX API key
Author
Built by jlhernando
License
ISC
