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-native-ble-scanner-kit

v2.0.2

Published

A React Native module for Bluetooth Low Energy (BLE) device scanning and management with distance estimation and device tracking capabilities

Readme

react-native-ble-scanner-kit

Proprietary software — Copyright (c) 2024 Ant-Tech. All rights reserved.
Unauthorized use is prohibited. See LICENSE for details.

npm: react-native-ble-scanner-kit

A React Native module for Bluetooth Low Energy (BLE) scanning with real-time distance estimation, per-device tracking, and proximity-based vibration/sound alerts. Native scanning uses SentiDriveBleModule (CoreBluetooth on iOS, BluetoothLeScanner on Android); filtering, Kalman smoothing, session guards, and pulse logic run in TypeScript.

Version 2.x is the New Architecture–oriented implementation (Turbo Module / bridgeless-friendly native patterns). It is published as 2.0.0 and upward on npm (previous line was 1.0.x).

Requirements

| Dependency | Version | | --- | --- | | React Native | >= 0.73.0 | | React | >= 18.0.0 | | Android minSdk | 24 | | iOS | 13.4+ |

Optional: react-native-sound-player — required only if you use scanConfig.enableSound / proximity tones.

Installation

npm install react-native-ble-scanner-kit
# or
yarn add react-native-ble-scanner-kit

For proximity sound, also install and link audio in the host app:

npm install react-native-sound-player

React Native autolinking picks up the library. Rebuild the native app after adding the dependency.

iOS

cd ios && pod install

Add to Info.plist:

<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to scan for nearby BLE devices.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app uses Bluetooth to scan for nearby BLE devices.</string>

Android

The library’s AndroidManifest.xml is merged into your app and declares BLE-related permissions (e.g. BLUETOOTH, BLUETOOTH_ADMIN, ACCESS_FINE_LOCATION where applicable, BLUETOOTH_SCAN, BLUETOOTH_CONNECT). Runtime BLE permissions on Android are requested from JavaScript when you call initializeBluetooth() (via PermissionsAndroid).

Migrating from 1.x (1.0.14 and earlier)

| Topic | 1.x | 2.x | | --- | --- | --- | | Package name | react-native-ble-scanner-kit | Same | | react-native-permissions | Documented as required peer | Not used — Android runtime BLE is handled inside initializeBluetooth() | | startScan | Returned emitter synchronously | Returns Promise<typeof DeviceEventEmitter> — use await startScan(...) | | CocoaPods pod | Legacy pod name | Pod name react-native-ble-scanner-kit (see react-native-ble-scanner-kit.podspec) |

Update imports to the same package name; add await before startScan and keep calling stopScan() on unmount.

Quick start

import {
  initializeBluetooth,
  startScan,
  stopScan,
} from 'react-native-ble-scanner-kit';

// 1. Initialize (Android runtime permissions + native Bluetooth)
await initializeBluetooth();

// 2. Start scanning — 2.x is async
const emitter = await startScan();

// 3. Listen for devices
const sub = emitter.addListener('onDeviceFound', (device) => {
  console.log(device.id, device.name, device.rssi, device.estimatedDistance);
});

// 4. Stop when done
sub.remove();
stopScan();

Hook example:

useEffect(() => {
  let sub: { remove: () => void } | undefined;
  let cancelled = false;

  (async () => {
    try {
      await initializeBluetooth();
      if (cancelled) return;
      const emitter = await startScan();
      sub = emitter.addListener('onDeviceFound', handleDevice);
    } catch (e) {
      console.error(e);
    }
  })();

  return () => {
    cancelled = true;
    sub?.remove();
    stopScan();
  };
}, []);

API reference

initializeBluetooth(): Promise<void>

Prepares BLE on the device. On Android, requests required runtime permissions. On iOS, relies on Info.plist strings and user consent. Then calls native initializeBluetooth.

Throws if permissions are denied or Bluetooth is unusable; also emits onError with structured codes where applicable.

try {
  await initializeBluetooth();
} catch (error) {
  console.error(error instanceof Error ? error.message : error);
}

startScan(targetId?, config?, isUseDeviceID?): Promise<typeof DeviceEventEmitter>

Starts a BLE scan and resolves to an event emitter (same listener API as typical RN patterns).

| Parameter | Type | Default | Description | | --- | --- | --- | --- | | targetId | string | undefined | If set, only matching devices are surfaced (see isUseDeviceID). | | config | SentiDriveScanConfigs | See below | Duration, RSSI model, Kalman, pulse tiers, vibration/sound flags. | | isUseDeviceID | boolean | false | If true, targetId is matched against hardware id (MAC / UUID, normalized). If false, matched against advertised name. |

Default configuration (merged in JS):

{
  scanConfig: {
    scanDuration: 30000,
    enableVibration: false,
    enableSound: false,
    txPower: -59,
    n: 2,
  },
  rssiFilter: {
    enableKalmanFilter: false,
    kalmanProcessNoise: 0.01,
    kalmanMeasurementNoise: 0.25,
  },
  // Default pulse tiers (see src/pulse.ts)
  pulseConfigs: [
    { distance: 1, intervalMs: 500 },
    { distance: 3, intervalMs: 1000 },
    { distance: 5, intervalMs: 2000 },
    { distance: 10, intervalMs: 3000 },
    { distance: 20, intervalMs: 5000 },
  ],
}

Filter by hardware id (e.g. MAC-style id):

const emitter = await startScan(
  'AA:BB:CC:DD:EE:FF',
  {
    scanConfig: {
      scanDuration: 60000,
      enableVibration: true,
      txPower: -65,
      n: 2.5,
    },
    rssiFilter: {
      enableKalmanFilter: true,
      kalmanProcessNoise: 0.01,
      kalmanMeasurementNoise: 0.5,
    },
    pulseConfigs: [
      { distance: 10, intervalMs: 2000 },
      { distance: 3, intervalMs: 500 },
    ],
  },
  true, // isUseDeviceID
);

Scan all devices:

const emitter = await startScan();

emitter.addListener('onDeviceFound', (device) => {
  console.log(`${device.name} is ~${device.estimatedDistance.toFixed(1)}m away`);
});

Behavior notes (2.x):

  • Session id — Events from a previous scan are ignored after stopScan or a new startScan.
  • Android — A minimum ~500 ms delay is applied after stopScan before the next native startScan to reduce scan throttling.
  • Device lost — If a device is not seen for ~5 s, it is removed from tracking and onDeviceLost fires.

stopScan(): void

Stops scanning, clears timers, device trackers, and pulse state, and detaches internal listeners. Emits onStopped with message "Stopped". Safe to call when idle.

Always call stopScan() when leaving a screen or unmounting a component that started a scan.


estimateDistance(rssi: number, txPower: number, n: number): number

Log-distance path loss (meters):

distance = 10 ^ ((txPower - rssi) / (10 * n))


getBluetoothStatus(): Promise<BluetoothStatus>

Returns the adapter state (on, off, unauthorized, unsupported, etc.).


openBluetoothSettings(): void

Opens system settings relevant to Bluetooth on each platform.


onBluetoothStatusChange(callback): () => void

Subscribe to onBluetoothStateChanged; returns an unsubscribe function.


setDebugEnabled(enabled: boolean): void

Toggles verbose internal logging where implemented.


setSoundFileName(fileName: string): void

Default asset name for proximity sound (default alert.mp3). Requires react-native-sound-player in the host app and the file in native bundles (res/raw on Android, main bundle on iOS).


startVibration(duration?: number): void

Triggers a one-shot vibration (default 400 ms on Android path; iOS may use native haptic when available).


KalmanFilter

Exported 1D Kalman helper for custom RSSI smoothing (processNoise, measurementNoise, update, reset).


Device tracker helpers

Used internally by startScan; exported for advanced/testing use:
updateDeviceTracker, clearDeviceTimer, startDeviceLostTimer, clearAllDeviceTrackers.

Pulse / sound helpers

updatePulseForDevice, clearPulseForDevice, pulseDeviceKey, playSound, stopSound.

Debug / introspection

getIsScanning, getLastStopAt, DeviceEventEmitter, NativeSentiDriveModule, teardownNativeBridge.


Events

Subscribe on the emitter returned from await startScan() (or import DeviceEventEmitter from the package).

| Event | Payload | Description | | --- | --- | --- | | onDeviceFound | DeviceFoundEvent | Device update with smoothed RSSI and estimatedDistance. | | onDeviceLost | { id, name, lastSeenAt } | No advertisement for ~5 s. | | onStopped | { message } | e.g. "Stopped" or "Timeout". | | onError | ErrorEvent | BT_OFF, PERMISSION_DENIED, SCAN_FAILED, etc. | | onBluetoothStateChanged | { bluetoothStatus } | Adapter state changes. | | onScanResult | raw | Internal — prefer onDeviceFound in app code. |

emitter.addListener('onError', ({ code, message }) => {
  console.error(`[${code}] ${message}`);
});

Types (summary)

type BluetoothStatus =
  | 'on' | 'off' | 'turningOff' | 'turningOn'
  | 'unauthorized' | 'unsupported' | 'resetting' | 'unknown';

type DeviceFoundEvent = {
  id: string;
  name: string;
  rssi: number;
  estimatedDistance: number;
  lastSeenAt?: number;
};

type ScanConfigs = {
  scanDuration?: number | null;
  enableVibration?: boolean;
  enableSound?: boolean;
  txPower?: number;
  n?: number;
};

type RSSIFilter = {
  enableKalmanFilter?: boolean;
  kalmanProcessNoise?: number;
  kalmanMeasurementNoise?: number;
};

type PulseConfig = { distance: number; intervalMs: number };

type SentiDriveScanConfigs = {
  scanConfig?: ScanConfigs;
  rssiFilter?: RSSIFilter;
  pulseConfigs?: PulseConfig[];
};

type ErrorEvent = {
  code:
    | 'BT_OFF'
    | 'PERMISSION_DENIED'
    | 'DEVICE_NOT_FOUND'
    | 'SCAN_FAILED'
    | 'NOT_SUPPORTED'
    | 'INVALID_TARGET_ID'
    | 'IOS_FOREGROUND_REQUIRED';
  message: string;
};

Full definitions: src/types.ts / published dist/*.d.ts.


Distance estimation

  • txPower: RSSI at 1 m (calibrate per beacon/hardware).
  • n: path-loss exponent (often 2 free space, 2.5–4 indoors).
  • Kalman: optional RSSI smoothing before distance is recomputed.

Pulse (proximity) alerts

pulseConfigs define distance bands and alert intervals. While scanning, enableVibration / enableSound turn on tiered feedback; sound uses react-native-sound-player when installed.


Development (library workspace)

npm run build   # TypeScript → dist/
npm test

License

SEE LICENSE IN LICENSE — see LICENSE.