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

@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

npm version License: MIT TypeScript

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-metrics

Linking 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:android

Performance 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; // 4

Levels (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;// 4

Collection 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[]PerformanceClass values (CPU=0, MEMORY=1, STORAGE=2, NETWORK=3, BATTERY=4). Only these are collected; others are null in 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:
    cd android && ./gradlew clean && cd ..
    npx react-native start --reset-cache
    Reinstall deps if needed: rm -rf node_modules && npm install.
  • Collection never fires — Call await DeviceMetrics.init() before any start* method.

Publishing

Manual release

  1. Ensure you're logged in to npm: npm login
  2. Commit all changes, clean working tree.
  3. Build: yarn prepare
  4. Bump: npm version patch (or minor / major)
  5. Publish: npm publish --access public
  6. Push: git push && git push --tags

Automated (release-it)

yarn release

This bumps version, tags, publishes to npm, and can create a GitHub release (if configured).


Contributing

  1. Fork the repo
  2. Create a branch (git checkout -b feature/your-feature)
  3. Commit (git commit -m 'feat: your change')
  4. Push (git push origin feature/your-feature)
  5. Open a Pull Request

See CONTRIBUTING.md and CODE_OF_CONDUCT.md.


License

MIT — see LICENSE.


Related

Built by Lokal.