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

@blife/rn-step-counter

v1.3.0

Published

This library provides an interface for tracking the number of steps taken by the user in a React Native app.

Readme

@blife/rn-step-counter

npm version npm downloads license

A React Native TurboModule for live step counting on iOS and Android.

Features

  • iOS — Core Motion (CMPedometer) with floors ascended/descended when available
  • Android — Hardware step counter (TYPE_STEP_COUNTER) with accelerometer fallback
  • New Architecture — TurboModule / Fabric (required)
  • Live updates — Event-based API with start/stop lifecycle
  • Historical query (iOS) — queryPedometerDataBetweenDates() for cumulative steps in a date range
  • Native events — Optional listeners for errors, sensor metadata, and step detection
  • Optional filtering — createStepCountFilter() reduces false positives from rapid motion
  • Utilities — parseStepData() for display-friendly formatting

Requirements

| | | |---|---| | React Native | >= 0.71.0 | | Architecture | New Architecture (TurboModules) | | Expo | Not supported in Expo Go (native module) | | Autolinking | React Native 0.60+ |

Installation

npm install @blife/rn-step-counter
yarn add @blife/rn-step-counter
# or
pnpm add @blife/rn-step-counter
# or
bun add @blife/rn-step-counter

Rebuild the native app after installing:

# iOS
cd ios && pod install && cd ..

# Android / iOS
npx react-native run-android
npx react-native run-ios

Platform setup

Android

Add permissions and sensor features to your app manifest if they are not already present:

<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

<uses-feature
  android:name="android.hardware.sensor.stepcounter"
  android:required="false" />
<uses-feature
  android:name="android.hardware.sensor.accelerometer"
  android:required="true" />

Request runtime permission before starting updates. The library reports permission status via isStepCountingSupported().

iOS

Add a motion usage description to your app's Info.plist:

<key>NSMotionUsageDescription</key>
<string>This app uses motion data to count your steps.</string>

Quick start

import { useEffect, useState } from "react";
import {
  createStepCountFilter,
  isStepCountingSupported,
  parseStepData,
  startStepCounterUpdate,
  stopStepCounterUpdate,
} from "@blife/rn-step-counter";

export function StepCounterScreen() {
  const [steps, setSteps] = useState(0);

  useEffect(() => {
    let active = true;

    (async () => {
      const { supported, granted } = await isStepCountingSupported();
      if (!active || !supported || !granted) {
        return;
      }

      const filter = createStepCountFilter();

      startStepCounterUpdate(new Date(), (data) => {
        const filtered = filter(data);
        if (!filtered) {
          return;
        }
        setSteps(filtered.steps);
      });
    })();

    return () => {
      active = false;
      stopStepCounterUpdate();
    };
  }, []);

  return null; // render your UI, e.g. parseStepData(...)
}

See the full example app: example/src/App.tsx.

API

isStepCountingSupported()

Returns Promise<{ supported: boolean; granted: boolean; working?: boolean }>.

  • supported — device can count steps (hardware sensor or fallback)
  • granted — required motion/activity permission has been granted
  • working — Android only: whether the native sensor service is currently active

queryPedometerDataBetweenDates(start, end) (iOS only)

Queries cumulative step data for the given range using Core Motion. Returns Promise<StepCountData>.

Apple retains roughly seven days of pedometer history; older ranges may return partial data. Does not interfere with an active live session. On Android, throws UnavailabilityError.

import { queryPedometerDataBetweenDates } from "@blife/rn-step-counter";

const start = new Date();
start.setHours(0, 0, 0, 0);
const today = await queryPedometerDataBetweenDates(start, new Date());

startStepCounterUpdate(start, callback)

Starts native step updates from start (JavaScript Date) and invokes callback with StepCountData on each event.

On iOS, steps and distance are both cumulative for [start, now], matching queryPedometerDataBetweenDates. A seed query runs immediately so the first event is today's total, not a delta since subscribe.

Returns an EventSubscription. Call stopStepCounterUpdate() to stop.

stopStepCounterUpdate()

Stops the active native session and removes the library's event subscription.

isSensorWorking()

Returns true when this library has an active subscription from startStepCounterUpdate. This reflects the JS-managed session, not Android's native working flag.

Event listeners

Subscribe to native events with the helpers below. Each returns an EventSubscription.

import {
  addStepCounterErrorListener,
  addStepsSensorInfoListener,
  addStepDetectedListener,
  addPedometerEventListener,
} from "@blife/rn-step-counter";

const errorSub = addStepCounterErrorListener((error) => {
  console.warn(error.message);
});
errorSub.remove();
  • addStepCounterErrorListener — StepCounter.errorOccurred (iOS Core Motion errors)
  • addStepsSensorInfoListener — StepCounter.stepsSensorInfo (capability metadata; fired from isStepCountingSupported on iOS and when the Android sensor starts)
  • addStepDetectedListener — StepCounter.stepDetected (native motion-detector signal; not tied to each cumulative step update)
  • addPedometerEventListener — StepCounter.pedometerEvent (iOS pause/resume; requires an active startStepCounterUpdate session)

createStepCountFilter(options?)

Returns a stateful filter function. Drops bursts that exceed the configured cadence (default: 250 ms per step) and rebases cumulative counts so ignored steps are not applied later.

A burst is dropped only when both the gap since the last event and the batch window (startDate→endDate) are too short for the new steps. That keeps fused CMPedometer deliveries after the app returns to the foreground. Pass { enabled: false } to skip cadence filtering.

parseStepData(data)

Formats raw StepCountData for display (steps, distance, time range, estimated calories, daily goal progress).

StepCountData

| Field | Type | Description | |-------|------|-------------| | steps | number | Cumulative steps for [startDate, endDate] | | startDate | number | Interval start (Unix ms) | | endDate | number | Interval end (Unix ms) | | distance | number | Distance in meters | | counterType | CounterType | "CMPedometer" · "STEP_COUNTER" · "ACCELEROMETER" | | floorsAscended | number? | iOS only | | floorsDescended | number? | iOS only | | calories | number? | Estimated calories when provided by native | | currentPaceSecPerM | number? | iOS only — current pace (seconds per meter) | | averageActivePaceSecPerM | number? | iOS only — average active pace (seconds per meter) | | currentCadenceStepsPerSec | number? | iOS only — step rate (steps per second) |

Development

bun install
bun run prepare
bun run test
bun run example:start   # Metro
bun run example:ios     # or example:android

See CONTRIBUTING.md for the full workflow.

Changelog

See CHANGELOG.md.

License

MIT