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

react-performance-tracking

v1.2.1

Published

React performance profiling with Playwright test integration

Readme

react-performance-tracking

npm version CI codecov License: MIT PRs Welcome

Automate React render performance checks in Playwright. Capture React Profiler metrics, apply CPU throttling, run warmups, enforce budgets (duration + rerenders, optional FPS), and ship JSON artifacts for debugging.

Why Use This?

  • Catch performance regressions early – Detect slow renders before they reach production
  • Real-world conditions – Test with CPU throttling, network throttling, and device simulation
  • CI/CD integration – Fail builds automatically when performance budgets are exceeded
  • Comprehensive metrics – Track React renders, FPS, memory usage, and Core Web Vitals
  • Zero boilerplate – Drop-in Playwright integration with minimal configuration

Quick Links

Features

  • 📊 React Profiler wiring – Collect real render metrics via React's Profiler API
  • 🎭 Playwright integrationtest.performance() helper and performance fixture
  • 🧩 Component-level profiling – Track per-component metrics with multiple profilers
  • 🎞️ FPS tracking (Chromium/CDP) – Measure avg FPS via tracing; asserts and logs when enabled
  • 🧠 Memory tracking (Chromium/CDP) – Track heap growth to detect memory leaks
  • 📈 Web Vitals tracking – Capture LCP, INP, CLS via PerformanceObserver (all browsers)
  • 🔦 Lighthouse audits (Chromium/CDP) – Run Lighthouse for performance, accessibility, SEO scores
  • 🐢 CPU throttling (Chromium/CDP) – Simulate slower devices when supported
  • 🌐 Network throttling (Chromium/CDP) – Simulate slow networks (3G/4G presets or custom)
  • ⏱️ Custom metrics – Track custom performance marks and measures for fine-grained timing
  • 🔥 Warmup runs – Default on CI to reduce cold-start noise
  • 🔄 Multiple iterations – Run tests multiple times and aggregate results for statistical reliability
  • 📊 Percentile metrics – P50/P95/P99 thresholds for tests with multiple iterations
  • 🔥 Trace export (Chromium/CDP) – Export Chrome DevTools traces for flamegraph visualization
  • ⚙️ Configurable thresholds – Separate local/CI budgets with optional buffers
  • 📝 Detailed logging – Clear console output with thresholds, FPS, memory, component breakdown, and phase breakdown
  • 📎 Artifacts – Attach performance JSON (metrics + config) to test reports

Installation

npm install react-performance-tracking

Alternative: Install from GitHub Release

If the npm package is not yet published, you can install directly from a GitHub release tarball:

# Download and install a specific version
npm install https://github.com/mkaczkowski/react-performance-tracking/releases/download/v1.1.0/react-performance-tracking-1.1.0.tgz

Or build from source:

git clone https://github.com/mkaczkowski/react-performance-tracking.git
cd react-performance-tracking
npm install && npm run build && npm pack
npm install ./react-performance-tracking-*.tgz

Peer Dependencies (optional)

{
  "react": "^18.0.0 || ^19.0.0",
  "@playwright/test": "^1.40.0",
  "lighthouse": ">=11.0.0"
}

Install only what you use:

  • react for the provider/hooks
  • @playwright/test for the Playwright integration
  • lighthouse for Lighthouse audits (install with npm install -D lighthouse)

Note: You may see peer dependency warnings during install (e.g., npm warn peer react@...). These are expected and can be safely ignored - all peer dependencies are marked as optional, so you only need to install the ones you actually use.

Quick Start

1) Wrap your app

import { Profiler } from 'react';
import { PerformanceProvider, usePerformanceRequired } from 'react-performance-tracking/react';

function App() {
  return (
    <PerformanceProvider>
      <Header />
      <MainContent />
    </PerformanceProvider>
  );
}

// Each component wrapped with Profiler gets its own metrics
function Header() {
  const { onProfilerRender } = usePerformanceRequired();
  return (
    <Profiler id="header" onRender={onProfilerRender}>
      <header>Navigation here</header>
    </Profiler>
  );
}

function MainContent() {
  const { onProfilerRender } = usePerformanceRequired();
  return (
    <Profiler id="main-content" onRender={onProfilerRender}>
      <main>Your component content</main>
    </Profiler>
  );
}

// Test output shows per-component tables when multiple components are profiled

2) Extend Playwright

// test/performance.setup.ts
import { test as base } from '@playwright/test';
import { createPerformanceTest } from 'react-performance-tracking/playwright';

export const test = createPerformanceTest(base);
export { expect } from '@playwright/test';

3) Write a performance test

// test/my-page.perf.spec.ts
import { test } from './performance.setup';

test.describe('My Page Performance', () => {
  // Simple test with basic thresholds
  test.performance({
    thresholds: {
      base: {
        profiler: {
          '*': { duration: 500, rerenders: 20 },
        },
      },
    },
  })('page load performance', async ({ page, performance }) => {
    await page.goto('/my-page');
    await performance.init();
    // Assertions run automatically
  });

  // Test user interactions
  test.performance({
    thresholds: { base: { profiler: { '*': { duration: 100, rerenders: 5 } } } },
  })('button click interaction', async ({ page, performance }) => {
    await page.goto('/my-page');
    await performance.init();

    await performance.reset(); // Isolate the interaction
    await page.click('button[data-testid="submit"]');
    await performance.waitUntilStable();
  });
});
test.performance({
  warmup: true, // Run warmup iteration (default: true on CI)
  throttleRate: 4, // Simulate 4x slower CPU
  iterations: 3, // Run 3 times for statistical reliability
  networkThrottling: 'fast-3g', // Simulate 3G network
  thresholds: {
    base: {
      profiler: {
        '*': { duration: 500, rerenders: 20 },
      },
      fps: 55, // Min 55 FPS (auto-enables FPS tracking)
      memory: { heapGrowth: 10 * 1024 * 1024 }, // Max 10MB heap growth (auto-enables memory tracking)
      webVitals: { lcp: 2500, inp: 200, cls: 0.1 }, // Auto-enables Web Vitals tracking
    },
    ci: {
      profiler: { '*': { duration: 600 } }, // More lenient in CI
    },
  },
})('comprehensive performance test', async ({ page, performance }) => {
  await page.goto('/my-page');
  await performance.init();
});

More Examples

test.describe('Advanced Usage', () => {
  // Track custom timing metrics
  test.performance({
    thresholds: { base: { profiler: { '*': { duration: 500, rerenders: 20 } } } },
  })('data loading with custom metrics', async ({ page, performance }) => {
    await page.goto('/my-page');
    await performance.init();

    performance.mark('fetch-start');
    await page.click('button[data-testid="load-data"]');
    await page.waitForSelector('.data-loaded');
    performance.mark('fetch-end');

    performance.mark('render-start');
    await performance.waitUntilStable();
    performance.mark('render-end');

    // Create measures for each operation
    const fetchTime = performance.measure('data-fetch', 'fetch-start', 'fetch-end');
    const renderTime = performance.measure('data-render', 'render-start', 'render-end');

    console.log(`Fetch: ${fetchTime}ms, Render: ${renderTime}ms`);
    // Custom metrics are automatically included in test output and artifacts
  });
});

Advanced Usage: Custom Fixtures

When using createPerformanceTest(), only page and performance fixtures are passed to your test function. If you need custom fixtures (like page objects, mocks, etc.), see the Custom Fixtures Guide.

API Overview

You can import from the root (react-performance-tracking) or subpaths (/react, /playwright).

React Exports

import {
  PerformanceProvider,
  usePerformance,
  usePerformanceRequired,
  usePerformanceStore,
} from 'react-performance-tracking/react';

Playwright Exports

Essential - what most users need:

import {
  createPerformanceTest,
  PERFORMANCE_CONFIG,
  NETWORK_PRESETS,
  setLogLevel,
} from 'react-performance-tracking/playwright';
import {
  // Building blocks for custom wrappers
  createPerformanceInstance,
  createConfiguredTestInfo,
  addConfigurationAnnotation,
  PerformanceTestRunner,

  // Assertions
  assertPerformanceThresholds,
  assertDurationThreshold,
  assertSampleCountThreshold,
  assertFPSThreshold,
  assertHeapGrowthThreshold,

  // CDP Feature system
  featureRegistry,
  cpuThrottlingFeature,
  networkThrottlingFeature,
  fpsTrackingFeature,
  memoryTrackingFeature,
  createFeatureCoordination,

  // Feature utilities
  createCDPSession,
  createFeatureHandle,
  createResettableFeatureHandle,

  // Network utilities
  resolveNetworkConditions,
  formatNetworkConditions,
  isNetworkPreset,

  // Profiler utilities
  captureProfilerState,
  logger,
} from 'react-performance-tracking/playwright';

Configuration Options

test.performance() config

test.performance({
  warmup?: boolean;        // default: true on CI, false locally
  throttleRate?: number;   // default: 1 (no throttling)
  iterations?: number;     // default: 1 (single run)
  networkThrottling?: NetworkThrottlingConfig; // preset or custom (Chromium only)
  exportTrace?: boolean | string; // export trace for flamegraph (Chromium only)
  thresholds: {
    base: {
      profiler: {
        '*': {           // Default for all components
          duration: number | { avg?: number; p50?: number; p95?: number; p99?: number };
          rerenders: number;
        };
        // Additional component IDs can be specified
        // 'header'?: { duration: 100, rerenders: 5 };
      };
      fps?: number | { avg?: number; p50?: number; p95?: number; p99?: number }; // Min FPS (auto-enables FPS tracking, Chromium only)
      memory?: {
        heapGrowth?: number; // max heap growth in bytes (auto-enables memory tracking, Chromium only)
      };
      webVitals?: {        // Web Vitals thresholds (auto-enables tracking, all browsers)
        lcp?: number;      // max LCP in ms (Google recommends ≤2500)
        inp?: number;      // max INP in ms (Google recommends ≤200)
        cls?: number;      // max CLS score (Google recommends ≤0.1)
      };
    };
    ci?: {               // Overrides for CI environment
      profiler?: {
        [componentId: string]: Partial<ComponentThresholds>;
      };
      fps?: number | { avg?: number; p50?: number; p95?: number; p99?: number };
      memory?: { heapGrowth?: number };
      webVitals?: { lcp?: number; inp?: number; cls?: number };
    };
  };
  buffers?: {
    duration?: number;     // % buffer (default: 20) - also used for duration percentiles (p50, p95, p99)
    rerenders?: number;    // % buffer (default: 20)
    fps?: number;          // % buffer (default: 20) - also used for fps percentiles (p50, p95, p99)
    heapGrowth?: number;   // % buffer (default: 20)
    webVitals?: { lcp?: number; inp?: number; cls?: number }; // % buffers (default: 20 each)
  };
  name?: string;           // artifact name
})('test title', async ({ page, performance }) => { ... });

// NetworkThrottlingConfig can be:
// - Preset: 'slow-3g' | 'fast-3g' | 'slow-4g' | 'fast-4g' | 'offline'
// - Custom: { latency: number, downloadThroughput: number, uploadThroughput: number, offline?: boolean }

Performance fixture methods

  • init() – Wait for profiler initialization and stability
  • reset() – Clear collected samples and custom metrics (isolate measurements)
  • waitForInitialization(timeout?) – Wait for profiler to be ready
  • waitUntilStable(options?) – Wait for React to settle
  • mark(name) – Record a custom performance mark (timestamp)
  • measure(name, startMark, endMark) – Create a measure between two marks (returns duration in ms)
  • getCustomMetrics() – Get all recorded marks and measures

Default Configuration

const PERFORMANCE_CONFIG = {
  profiler: {
    stabilityPeriodMs: 1000,
    checkIntervalMs: 100,
    maxWaitMs: 5000,
    initializationTimeoutMs: 10000,
  },
  buffers: {
    duration: 20,
    rerenders: 20,
    avg: 20,
    heapGrowth: 20,
    webVitals: { lcp: 20, inp: 20, cls: 20 },
  },
  throttling: {
    defaultRate: 1,
  },
  fps: {
    defaultThreshold: 60,
  },
  memory: {
    defaultThreshold: 0, // 0 = no threshold, just track
  },
  webVitals: {
    enabled: false, // off by default to avoid overhead
  },
  iterations: {
    defaultCount: 1,
  },
  get isCI() {
    return Boolean(process.env.CI);
  },
};

Controlling Log Output

import { setLogLevel } from 'react-performance-tracking/playwright';

// Available levels: 'silent' | 'error' | 'warn' | 'info' | 'debug'
setLogLevel('silent'); // Disable all console output
setLogLevel('error'); // Only show errors
setLogLevel('info'); // Default - show info, warnings, errors

Environment Behavior

| Environment | Thresholds Used | Warmup Default | | ----------- | ----------------------- | -------------- | | CI | base merged with ci | true | | Local | base only | false |

Console Output

════════════════════════════════════════════════════════════════════════════════
 [Performance] PERFORMANCE TEST: page-load-performance
════════════════════════════════════════════════════════════════════════════════
 Environment: local | CPU: 4x | Iterations: 3
────────────────────────────────────────────────────────────────────────────────

 ITERATIONS
┌─────┬─────────────┬─────────┬───────┐
│ #   │ Duration    │ Renders │ FPS   │
├─────┼─────────────┼─────────┼───────┤
│ 1 ○ │     35.20ms │      26 │  29.6 │
│ 2   │     22.50ms │      26 │  47.4 │
│ 3   │     21.60ms │      26 │  50.5 │
├─────┼─────────────┼─────────┼───────┤
│ AVG │ 22.05ms ±0.5│  26 ±0.0│  49.0 │
└─────┴─────────────┴─────────┴───────┘
 ○ = warmup (excluded from average)

 RESULTS
┌──────────┬──────────┬───────────┬────────┐
│ Metric   │ Actual   │ Threshold │ Status │
├──────────┼──────────┼───────────┼────────┤
│ Duration │ 22.05ms  │  < 600ms  │ ✓ PASS │
│ Renders  │       26 │      ≤ 24 │ ✓ PASS │
│ FPS      │     49.0 │    ≥ 44.0 │ ✓ PASS │
│ LCP      │  1523ms  │  ≤ 3000ms │ ✓ PASS │
│ INP      │    85ms  │   ≤ 240ms │ ✓ PASS │
│ CLS      │    0.050 │    ≤ 0.12 │ ✓ PASS │
└──────────┴──────────┴───────────┴────────┘

════════════════════════════════════════════════════════════════════════════════
 ✓ ALL CHECKS PASSED
════════════════════════════════════════════════════════════════════════════════

Troubleshooting

Tests timing out?

  • Increase initialization timeout: Adjust initializationTimeoutMs in your config
  • Check PerformanceProvider: Ensure it wraps your app root component
  • Verify profiler IDs: Make sure <Profiler id="..."> IDs match your test expectations
// Extend timeout if needed
await performance.waitForInitialization(15000); // 15 seconds instead of default 10s

FPS tracking not working?

  • Browser requirement: FPS tracking requires Chromium (Chrome/Edge)
  • Enable in config: Add fps thresholds to automatically enable FPS tracking
  • Check CDP availability: Non-Chromium browsers will silently skip FPS tracking

Thresholds failing unexpectedly?

  • Environment differences: Check if you're running in CI vs local (different thresholds apply)
  • Review buffers: Default buffer is 20% - adjust in config if needed
  • Component-specific thresholds: Use per-component thresholds for fine-grained control
thresholds: {
  base: {
    profiler: {
      '*': { duration: 500, rerenders: 20 },
    },
  },
  ci: {
    profiler: {
      '*': { duration: 600 }, // More lenient in CI
    },
  },
},
buffers: {
  duration: 10, // Reduce buffer to 10%
},

Memory or network throttling not applying?

  • Chromium only: These features require Chromium browser
  • Check config: Verify memory.heapGrowth threshold or networkThrottling config is set
  • Session conflicts: Ensure no other tools are using CDP on the same page

Need more help?

Limitations

  • CPU throttling, FPS tracking, memory tracking, and network throttling require Chromium/CDP; other browsers skip them quietly.
  • React Profiler must be enabled in production builds if you test prod bundles.
  • When using createPerformanceTest(), only page and performance fixtures are exposed. Use the building blocks directly if you need custom fixtures (see Advanced Usage above).

Requirements

  • React 18+ or 19+
  • Playwright 1.40+
  • Node.js 18+

License

MIT