@lokal-dev/react-native-device-metrics
v1.0.0
Published
Real-time device performance monitoring and telemetry for React Native (Android)
Readme
@lokal-dev/react-native-device-metrics
Real-time device performance monitoring and telemetry for React Native. Collect CPU, memory, network, storage, and battery metrics with configurable thresholds and event-driven streaming.
Android only. This library does not support iOS.
Features
- Real-time monitoring — Background collection at configurable intervals
- Two collection modes — Raw metrics only, or detailed (raw + performance levels per class)
- Metrics — CPU, memory, network, storage, battery
- Dual architecture — Old React Native bridge and TurboModule
- Event-driven — Real-time updates via
DeviceEventEmitter - TypeScript — Full type definitions
- Configurable thresholds — Tune performance classification (low / average / high / excellent)
Requirements
| Platform | Version / Notes | | -------------------- | ---------------------------------- | | React Native CLI | 0.73+ | | Expo (dev client)| SDK 50+ (not compatible with Expo Go) | | Android | API 24+ (Android 7.0) | | iOS | Not supported |
Android
- minSdkVersion: 24
- compileSdkVersion: 35+
This library depends on a native Android SDK published to GitHub Packages. The Android build must have access to that Maven repository (see Installation).
Installation
npm install @lokal-dev/react-native-device-metrics
# or
yarn add @lokal-dev/react-native-device-metricsLinking is automatic. You still need to configure the GitHub Packages Maven repo so the Android dependency can be resolved.
GitHub Packages (Android)
Set these environment variables (token needs read:packages):
export GITHUB_USERNAME="your-github-username"
export GITHUB_TOKEN="your-github-personal-access-token"React Native CLI
In your project’s project-level android/build.gradle:
allprojects {
repositories {
maven {
url = uri("https://maven.pkg.github.com/lokal-app/device-telemetry-toolkit")
credentials {
username = System.getenv("GITHUB_USERNAME") ?: ""
password = System.getenv("GITHUB_TOKEN") ?: ""
}
}
}
}Expo
Add the config plugin in app.json (it configures the Maven repo):
{
"expo": {
"plugins": ["@lokal-dev/react-native-device-metrics"]
}
}Then create a development build (Expo Go is not supported):
npx expo run:androidPerformance Classes & Levels
Classes (what you collect):
import { PerformanceClass } from '@lokal-dev/react-native-device-metrics';
PerformanceClass.CPU; // 0
PerformanceClass.MEMORY; // 1
PerformanceClass.STORAGE; // 2
PerformanceClass.NETWORK; // 3
PerformanceClass.BATTERY; // 4Levels (classification result):
import { PerformanceLevel } from '@lokal-dev/react-native-device-metrics';
PerformanceLevel.UNKNOWN; // 0
PerformanceLevel.LOW; // 1
PerformanceLevel.AVERAGE; // 2
PerformanceLevel.HIGH; // 3
PerformanceLevel.EXCELLENT;// 4Collection Flows
Two independent flows; both can run at the same time. Only shutdown() stops everything.
| | Raw collection | Detailed collection |
| ----------------------- | --------------------------- | -------------------------------------- |
| Data | Sensor/system values only | Raw + performanceLevel per class |
| Use case | Logging, custom logic | Ready-made performance assessment |
| Event | onRawPerformanceData | onDetailedPerformanceData |
| Overhead | Lower | Slightly higher (includes classification) |
Quick Start
1. Initialize
import * as DeviceMetrics from '@lokal-dev/react-native-device-metrics';
await DeviceMetrics.init();
// or with custom thresholds
await DeviceMetrics.init(customThresholds);2. Raw data collection
// Start CPU + memory every 15s
await DeviceMetrics.startRawPerformanceDataCollection(
[DeviceMetrics.PerformanceClass.CPU, DeviceMetrics.PerformanceClass.MEMORY],
15
);
const subscription = DeviceMetrics.addRawPerformanceDataListener((data) => {
console.log('CPU cores:', data.cpu?.coreCount);
console.log('Available RAM:', data.memory?.availableRamGB, 'GB');
});
await DeviceMetrics.updateRawPerformanceDataCollection(10); // change interval
await DeviceMetrics.stopRawPerformanceDataCollection();
subscription.remove();3. Detailed data collection
await DeviceMetrics.startDetailedPerformanceDataCollection(
[DeviceMetrics.PerformanceClass.CPU, DeviceMetrics.PerformanceClass.MEMORY],
15
);
const subscription = DeviceMetrics.addDetailedPerformanceDataListener((data) => {
console.log('CPU level:', data.cpu?.performanceLevel);
console.log('Memory level:', data.memory?.performanceLevel);
});
await DeviceMetrics.stopDetailedPerformanceDataCollection();
subscription.remove();4. One-shot weighted assessment
const results = await DeviceMetrics.getWeightedPerformanceLevels([
{ class: DeviceMetrics.PerformanceClass.CPU, weight: 2.0 },
{ class: DeviceMetrics.PerformanceClass.MEMORY, weight: 1.5 },
{ class: DeviceMetrics.PerformanceClass.NETWORK, weight: 1.0 },
]);
console.log('Overall:', results.overallPerformanceLevel);
console.log('CPU:', results.cpu, 'Memory:', results.memory);API Reference
Initialization & lifecycle
| Method | Description |
| ------------------- | ----------- |
| init(thresholds?) | Initialize the SDK. Call before any other API. |
| shutdown() | Stop all flows and reset. Call init() again to reuse. |
Raw collection
| Method | Description |
| ------ | ----------- |
| startRawPerformanceDataCollection(classes, delaySeconds) | Start periodic raw collection; emits onRawPerformanceData. |
| updateRawPerformanceDataCollection(delaySeconds) | Change interval; returns true if updated. |
| stopRawPerformanceDataCollection() | Stop raw collection only. |
| getLatestRawPerformanceData() | Last raw snapshot (parsed object, or null if none yet). |
| addRawPerformanceDataListener(callback) | Subscribe to raw events; returns EventSubscription. |
Detailed collection
| Method | Description |
| ------ | ----------- |
| startDetailedPerformanceDataCollection(classes, delaySeconds) | Start detailed collection; emits onDetailedPerformanceData. |
| updateDetailedPerformanceDataCollection(delaySeconds) | Change interval; returns true if updated. |
| stopDetailedPerformanceDataCollection() | Stop detailed collection only. |
| getLatestDetailedPerformanceData() | Last detailed snapshot (parsed object, or null if none yet). |
| addDetailedPerformanceDataListener(callback) | Subscribe to detailed events; returns EventSubscription. |
Performance levels
| Method | Description |
| ------ | ----------- |
| getWeightedPerformanceLevels(classesWithWeights) | One-shot weighted assessment. Returns a parsed WeightedPerformanceLevels object (overall + per-class levels as strings). |
| getPerformanceLevel(performanceClass) | Current performance level for one class. Returns a number: 0 (UNKNOWN), 1 (LOW), 2 (AVERAGE), 3 (HIGH), 4 (EXCELLENT). |
Parameters
classes:number[]—PerformanceClassvalues (CPU=0, MEMORY=1, STORAGE=2, NETWORK=3, BATTERY=4). Only these are collected; others arenullin the result.delaySeconds:number— Interval in whole seconds (min 1).
Stop vs shutdown
stopRawPerformanceDataCollection()/stopDetailedPerformanceDataCollection()— Stop that flow only; SDK stays initialized.shutdown()— Stop all flows and tear down the SDK.
Custom Thresholds
Pass a thresholds object into init() to customize how raw values map to performance levels (e.g. memory, battery, CPU). See the type definitions for the full shape; example for memory and battery:
const customThresholds = {
memory: {
low: { approxHeapRemainingInMBThreshold: 32, approxHeapLimitInMBThreshold: 64 },
average: { approxHeapRemainingInMBThreshold: 64, approxHeapLimitInMBThreshold: 128, availableRamGBThreshold: 1.5 },
high: { approxHeapRemainingInMBThreshold: 256, availableRamGBThreshold: 3 },
},
battery: {
excellent: { batteryPercentageThreshold: 80, isChargingBatteryPercentageThreshold: 70, temperatureThreshold: 30 },
high: { batteryPercentageThreshold: 55, isChargingBatteryPercentageThreshold: 50, temperatureThreshold: 34 },
average: { batteryPercentageThreshold: 40, isChargingBatteryPercentageThreshold: 35, temperatureThreshold: 38 },
},
// ... cpu, network, storage
};
await DeviceMetrics.init(customThresholds);Recommended Collection Intervals
| Use case | Interval (seconds) | | ------------------------- | ------------------- | | Background monitoring | 15–30 | | Active feature monitoring | 5–10 | | Call/video monitoring | 2–5 |
Troubleshooting
Build
- AGP / Kotlin version errors — Align Android Gradle Plugin and Kotlin versions with React Native 0.73+ (e.g. Kotlin 1.8.0+).
Runtime
Cannot read property 'init' of undefined— Clean build and Metro cache:
Reinstall deps if needed:cd android && ./gradlew clean && cd .. npx react-native start --reset-cacherm -rf node_modules && npm install.- Collection never fires — Call
await DeviceMetrics.init()before anystart*method.
Publishing
Manual release
- Ensure you're logged in to npm:
npm login - Commit all changes, clean working tree.
- Build:
yarn prepare - Bump:
npm version patch(orminor/major) - Publish:
npm publish --access public - Push:
git push && git push --tags
Automated (release-it)
yarn releaseThis bumps version, tags, publishes to npm, and can create a GitHub release (if configured).
Contributing
- Fork the repo
- Create a branch (
git checkout -b feature/your-feature) - Commit (
git commit -m 'feat: your change') - Push (
git push origin feature/your-feature) - Open a Pull Request
See CONTRIBUTING.md and CODE_OF_CONDUCT.md.
License
MIT — see LICENSE.
Related
- device-telemetry-toolkit — Native Android performance SDK used by this library.
Built by Lokal.
