React Native Performance API
react-native-performance is a library that brings a comprehensive implementation of the Web Performance API (User Timing Level 3 and Performance Timeline Level 2) to React Native applications. It provides high-resolution, monotonically increasing timestamps for accurate measurement, independent of system clock adjustments. The current stable version is 6.0.0, released in late 2024. The project maintains an active release cadence with frequent patch and minor updates, and major versions introducing breaking changes every few months. Key differentiators include its adherence to web standards, support for custom metrics, optional network resource logging (for fetch/XMLHttpRequest), and native marks for measuring core application startup and lifecycle events. It also offers the PerformanceObserver API for subscribing to performance entries and ships with full TypeScript type definitions.
Common errors
-
Soft exception when library tries to access `RCTDeviceEventEmitter` before it is initialized.
cause Timing issue on Android where the native module attempts to interact with JavaScript before it's fully ready.fixUpgrade to `react-native-performance` version 6.0.0 or later, which includes a fix for this specific Android issue. -
Errors or unexpected behavior when running in React Native's bridgeless mode.
cause Compatibility issues with the experimental bridgeless mode, often related to native module communication.fixUpgrade to `react-native-performance` version 5.1.4 or later, which contains fixes for bridgeless mode on both iOS and Android. -
iOS build failure when using custom native marks.
cause Issues with Xcode or Cocoapods configuration when integrating custom native marks.fixUpgrade to `react-native-performance` version 5.1.3 or later, which addresses a build failure on iOS related to custom native marks. -
TypeError: Cannot read property 'observe' of undefined (or 'PerformanceObserver is not a constructor')
cause `PerformanceObserver` was not correctly imported as a named export, or the import statement for `react-native-performance` is incorrect.fixEnsure you are using `import { PerformanceObserver } from 'react-native-performance';` and not a default import for `PerformanceObserver`.
Warnings
- breaking Version 6.0.0 removed support for several long-deprecated APIs and features, including Flipper integration, Flow-based Codegen (now TypeScript), and replaced `onCatalystInstanceDestroyed` with `invalidate` and `hasActiveCatalystInstance` with `hasActiveReactInstance`.
- breaking Version 5.0.0 introduced a new approach to measuring native startup time on iOS to prevent distorted or excessively high measurements, particularly on iOS 15+.
- breaking Version 4.0.0 made a breaking change where `react-native-performance` native marks switched back to using a monotonic clock. This change was necessary to support React Native 0.68.3 and above.
- gotcha Performance timestamps are high-resolution and monotonically increasing, meaning they are independent of system clock adjustments. To convert a performance timestamp to a Unix epoch timestamp, you must subtract `performance.timeOrigin` from `Date.now()` and then add the performance entry's `startTime`.
- gotcha Network resource logging is disabled by default and only covers `fetch`/`XMLHttpRequest` uses within React Native. It will not capture native network requests unless explicitly enabled.
Install
-
npm install react-native-performance -
yarn add react-native-performance -
pnpm add react-native-performance
Imports
- performance
import { performance } from 'react-native-performance';import performance from 'react-native-performance';
- PerformanceObserver
import PerformanceObserver from 'react-native-performance';
import { PerformanceObserver } from 'react-native-performance'; - setResourceLoggingEnabled
performance.setResourceLoggingEnabled(true);
import { setResourceLoggingEnabled } from 'react-native-performance'; - All common imports (CJS)
const performance = require('react-native-performance').default; const { PerformanceObserver, setResourceLoggingEnabled } = require('react-native-performance');
Quickstart
import performance, { PerformanceObserver, setResourceLoggingEnabled } from 'react-native-performance';
// Enable resource logging early in your app lifecycle if needed
setResourceLoggingEnabled(true);
// Observe performance measures and resources
const perfObserver = new PerformanceObserver((list) => {
list.getEntries().forEach((entry) => {
console.log(`[PerfEntry] ${entry.entryType}: ${entry.name} took ${entry.duration.toFixed(2)}ms`);
if (entry.entryType === 'resource') {
console.log(` - URL: ${entry.name}, Transfer Size: ${entry.transferSize} bytes`);
}
});
});
perfObserver.observe({ entryTypes: ['measure', 'resource', 'metric'], buffered: true });
async function simulateOperation() {
performance.mark('opStart', { detail: { type: 'apiCall', screen: 'home' } });
console.log('Fetching data...');
try {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const data = await response.json();
console.log('Data fetched:', data.title);
performance.mark('opEnd');
performance.measure('fetchDataOperation', 'opStart', 'opEnd', { detail: { status: 'success' } });
} catch (error) {
console.error('Fetch failed:', error);
performance.mark('opEnd');
performance.measure('fetchDataOperation', 'opStart', 'opEnd', { detail: { status: 'failed', error: String(error) } });
}
performance.metric('customMetricExample', Math.floor(Math.random() * 100));
}
simulateOperation();
// Example of converting performance timestamp to Unix epoch (optional)
// const timestamp = Date.now() - performance.timeOrigin + performance.now();
// console.log(`Current Unix epoch from performance: ${timestamp}`);