npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

Readme

crux-vitals

npm version

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 data

How 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 files

Core 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-vitals

Requires 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 --help

Get 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 --histogram

CLI 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 help

Output

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 fetch and --env-file)
  • CrUX API key

Author

Built by jlhernando

License

ISC