Works with Expo ββ’β Read the Documentation ββ’β Report Issues
munim-wifi is a comprehensive React Native library for Wi-Fi network scanning and analysis. This library allows your React Native app to scan for nearby Wi-Fi networks, retrieve detailed network information including SSIDs, BSSIDs (MAC addresses), RSSI (signal strength), channels, frequencies, and perform Wi-Fi fingerprinting for location-based services.
Fully compatible with Expo! Works seamlessly with both Expo managed and bare workflows.
Built with React Native's Nitro modules architecture for high performance and reliability.
Note: This library focuses on reliability and platform compatibility. It supports core Wi-Fi scanning features that work consistently across both Android and iOS platforms.
- π Documentation
- π Features
- π¦ Installation
- β‘ Quick Start
- π§ API Reference
- π Usage Examples
- π Troubleshooting
- π Contributing
- π License
Learn about building Wi-Fi scanning apps in our documentation!
- π‘ Network Scanning: Scan for nearby Wi-Fi networks with detailed information
- πΆ Signal Strength: Get RSSI (signal strength) values for all networks (Android only)
- π Network Details: Retrieve SSIDs, BSSIDs (MAC addresses), channels, and frequencies (Android only)
- π Wi-Fi Fingerprinting: Create comprehensive Wi-Fi fingerprints for location services
- π Continuous Scanning: Support for continuous scanning with event-based updates (Android only)
- π± Cross-platform: Works on both iOS and Android
- π Connect to Networks: Programmatically connect to Wi-Fi networks
- π Disconnect: Disconnect from current Wi-Fi network
- π± Current Network Info: Get information about currently connected network
- π IP Address: Retrieve IP address information for current connection
- π± Cross-platform: Works on both iOS and Android (with platform-specific limitations)
- π― TypeScript Support: Full TypeScript definitions included
- β‘ High Performance: Built with React Native's Nitro modules architecture
- π Expo Compatible: Works seamlessly with Expo managed and bare workflows
- π Permission Handling: Built-in permission request helpers
Critical: CoreWLAN is macOS Only
CoreWLAN framework is NOT available on iOS - it only works on macOS. The iOS implementation uses NEHotspotNetwork and NEHotspotConfiguration APIs.
iOS Wi-Fi Scanning Capabilities: iOS has very limited Wi-Fi scanning capabilities:
β Available on iOS:
- Get SSID (network name) - via
NEHotspotNetwork.fetchCurrent() - Get BSSID (MAC address) - via
NEHotspotNetwork.fetchCurrent() - Connect to Wi-Fi networks - via
NEHotspotConfiguration - Disconnect from Wi-Fi - via
NEHotspotConfiguration - Get current connected network info
β NOT Available on iOS:
- RSSI (signal strength) - Cannot be retrieved for scanned networks
- Channel information - Not available
- Frequency information - Not available
- General network scanning - Only works for hotspot networks via NEHotspotHelper (requires special entitlement)
iOS Requirements:
- Location permission (precise location) required
- "Access Wi-Fi Information" entitlement in Xcode
- "Hotspot Configuration" capability for connecting to networks
- iOS 13+ requires location permission
Scanning Restrictions:
WifiManager.startScan()is deprecated in Android P (API 28) but still works- Throttling limits:
- Foreground apps: 4 scans every 2 minutes
- Background apps: More restrictive
- Requires location permission (Android 6.0+)
- Passive listening available on Android 10+ (API 29)
β Available on Android:
- Full network scanning with SSID, BSSID, RSSI, channel, frequency
- Connect/disconnect to networks
- Get current network info
- All features work, but with throttling limits
| Feature | iOS | Android | Notes |
|---|---|---|---|
| Scan networks | β Full | iOS: SSID/BSSID only, no RSSI/channel/frequency | |
| Get SSID | β | β | Both platforms |
| Get BSSID | β | β | Both platforms |
| Get RSSI | β | β | iOS: Not available for scanned networks |
| Get Channel | β | β | iOS: Not available |
| Get Frequency | β | β | iOS: Not available |
| Connect to network | β | β | Both platforms (requires entitlements/capabilities) |
| Disconnect | β | β | Both platforms |
| Get current network | β | β | Both platforms |
| Wi-Fi fingerprinting | β Full | iOS: Limited to SSID/BSSID only |
npm install munim-wifi react-native-nitro-modules
# or
yarn add munim-wifi react-native-nitro-modulesnpx expo install munim-wifi react-native-nitro-modulesNote: This library requires Expo SDK 50+ and works with both managed and bare workflows. To support Nitro modules, you need React Native version v0.78.0 or higher.
For iOS, the library is automatically linked. However, you need to add the following to your Info.plist:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app uses location services to scan for nearby Wi-Fi networks</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app uses location services to scan for nearby Wi-Fi networks</string>For Expo projects, add these permissions to your app.json:
{
"expo": {
"ios": {
"infoPlist": {
"NSLocationWhenInUseUsageDescription": "This app uses location services to scan for nearby Wi-Fi networks",
"NSLocationAlwaysAndWhenInUseUsageDescription": "This app uses location services to scan for nearby Wi-Fi networks"
}
}
}
}For Android, add the following permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />For Expo projects, add these permissions to your app.json:
{
"expo": {
"android": {
"permissions": [
"android.permission.ACCESS_WIFI_STATE",
"android.permission.CHANGE_WIFI_STATE",
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.ACCESS_COARSE_LOCATION"
]
}
}
}import { scanNetworks, requestWifiPermission, isWifiEnabled } from 'munim-wifi'
// Check if Wi-Fi is enabled
const wifiEnabled = await isWifiEnabled()
if (!wifiEnabled) {
console.log('Wi-Fi is not enabled')
return
}
// Request permissions (required for scanning)
const hasPermission = await requestWifiPermission()
if (!hasPermission) {
console.log('Location permission not granted')
return
}
// Scan for networks
const networks = await scanNetworks()
console.log(`Found ${networks.length} networks`)
networks.forEach(network => {
console.log(`SSID: ${network.ssid}`)
console.log(`BSSID: ${network.bssid}`)
console.log(`RSSI: ${network.rssi} dBm`)
console.log(`Channel: ${network.channel}`)
console.log(`Frequency: ${network.frequency} MHz`)
console.log(`Secure: ${network.isSecure}`)
})import { getSSIDs, getRSSI, getBSSID, getChannelInfo, getNetworkInfo } from 'munim-wifi'
// Get all SSIDs
const ssids = await getSSIDs()
console.log('Available networks:', ssids)
// Get RSSI for a specific network
const rssi = await getRSSI('MyNetwork')
console.log('Signal strength:', rssi, 'dBm')
// Get BSSID (MAC address) for a network
const bssid = await getBSSID('MyNetwork')
console.log('BSSID:', bssid)
// Get channel information
const channelInfo = await getChannelInfo('MyNetwork')
if (channelInfo) {
console.log('Channel:', channelInfo.channel)
console.log('Frequency:', channelInfo.frequency, 'MHz')
}
// Get all information for a network
const networkInfo = await getNetworkInfo('MyNetwork')
if (networkInfo) {
console.log('Full network info:', networkInfo)
}import { getWifiFingerprint } from 'munim-wifi'
// Get Wi-Fi fingerprint (useful for location services)
const fingerprint = await getWifiFingerprint()
console.log('Fingerprint timestamp:', fingerprint.timestamp)
console.log('Networks found:', fingerprint.networks.length)
fingerprint.networks.forEach(network => {
console.log(`${network.ssid}: ${network.rssi} dBm on channel ${network.channel}`)
})import { startScan, stopScan, addNetworkFoundListener } from 'munim-wifi'
// Start continuous scanning
startScan()
// Listen for discovered networks
const unsubscribe = addNetworkFoundListener((network) => {
console.log('Network found:', network.ssid, network.rssi, 'dBm')
})
// Stop scanning when done
// stopScan()
// unsubscribe()Checks if Wi-Fi is enabled on the device.
Returns: Promise
Requests Wi-Fi permissions (Android) or checks authorization status (iOS). On Android, this requests location permission which is required for Wi-Fi scanning. On iOS, this checks location authorization status.
Returns: Promise
Scans for nearby Wi-Fi networks.
Parameters:
options?(object):maxResults?(number): Maximum number of results to returntimeout?(number): Timeout in milliseconds (default: 10000)
Returns: Promise<WifiNetwork[]>
Starts continuous Wi-Fi scanning. Results will be emitted via events.
Parameters:
options?(object):maxResults?(number): Maximum number of results to returntimeout?(number): Timeout in milliseconds
Stops continuous Wi-Fi scanning.
Gets list of SSIDs (network names) from the last scan.
Returns: Promise<string[]>
Gets Wi-Fi fingerprint containing all network information. This includes SSIDs, BSSIDs, RSSI, channels, and frequencies.
Returns: Promise
Gets RSSI (signal strength) for a specific network by SSID.
Parameters:
ssid(string): The SSID of the network
Returns: Promise<number | null>
Gets BSSID (MAC address) for a specific network by SSID.
Parameters:
ssid(string): The SSID of the network
Returns: Promise<string | null>
Gets channel and frequency information for a specific network by SSID. Note: Not available on iOS - returns null.
Parameters:
ssid(string): The SSID of the network
Returns: Promise<ChannelInfo | null>
Gets all available information for a specific network by SSID. Note: On iOS, RSSI, channel, and frequency will be undefined.
Parameters:
ssid(string): The SSID of the network
Returns: Promise<WifiNetwork | null>
Gets information about the currently connected Wi-Fi network.
Returns: Promise<CurrentNetworkInfo | null>
Connects to a Wi-Fi network. Note: Requires appropriate permissions and capabilities on both platforms.
Parameters:
options(ConnectionOptions):ssid(string): The SSID of the networkpassword?(string): Optional password for secured networksisWEP?(boolean): Whether the network uses WEP encryption
Returns: Promise
Disconnects from the current Wi-Fi network.
Returns: Promise
Gets IP address information for the current Wi-Fi connection.
Returns: Promise<string | null>
Adds a network found event listener (for continuous scanning).
Parameters:
callback(function): Function to call when a network is found
Returns: Function to remove the listener
Adds an event listener.
Parameters:
eventName(string): The name of the event to listen forcallback(function): The callback to invoke when the event occurs
Returns: Function to remove the listener
interface WifiNetwork {
ssid: string
bssid: string
rssi?: number // Not available on iOS
frequency?: number // Not available on iOS
channel?: number // Not available on iOS
capabilities?: string
isSecure?: boolean
timestamp?: number
}interface CurrentNetworkInfo {
ssid: string
bssid: string
ipAddress?: string
subnetMask?: string
gateway?: string
dnsServers?: string[]
}interface ConnectionOptions {
ssid: string
password?: string
isWEP?: boolean
}interface WifiFingerprint {
networks: WifiNetwork[]
timestamp: number
location?: {
latitude?: number
longitude?: number
}
}interface ScanOptions {
maxResults?: number
timeout?: number
}import React, { useState, useEffect } from 'react'
import { View, Text, FlatList, Button } from 'react-native'
import {
scanNetworks,
requestWifiPermission,
isWifiEnabled,
type WifiNetwork,
} from 'munim-wifi'
const NetworkScanner = () => {
const [networks, setNetworks] = useState<WifiNetwork[]>([])
const [scanning, setScanning] = useState(false)
const handleScan = async () => {
setScanning(true)
// Check Wi-Fi status
const wifiEnabled = await isWifiEnabled()
if (!wifiEnabled) {
alert('Please enable Wi-Fi')
setScanning(false)
return
}
// Request permissions
const hasPermission = await requestWifiPermission()
if (!hasPermission) {
alert('Location permission is required for Wi-Fi scanning')
setScanning(false)
return
}
// Scan networks
const results = await scanNetworks({ maxResults: 20 })
setNetworks(results)
setScanning(false)
}
return (
<View>
<Button
title={scanning ? 'Scanning...' : 'Scan Networks'}
onPress={handleScan}
disabled={scanning}
/>
<FlatList
data={networks}
keyExtractor={(item) => item.bssid}
renderItem={({ item }) => (
<View>
<Text>{item.ssid}</Text>
<Text>Signal: {item.rssi} dBm</Text>
<Text>Channel: {item.channel}</Text>
<Text>BSSID: {item.bssid}</Text>
<Text>Secure: {item.isSecure ? 'Yes' : 'No'}</Text>
</View>
)}
/>
</View>
)
}import { getWifiFingerprint } from 'munim-wifi'
const collectFingerprint = async () => {
const fingerprint = await getWifiFingerprint()
// Send fingerprint to your backend for location matching
await fetch('https://your-api.com/location', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
fingerprint: fingerprint.networks.map(n => ({
bssid: n.bssid,
rssi: n.rssi,
channel: n.channel,
})),
timestamp: fingerprint.timestamp,
}),
})
}import { startScan, addNetworkFoundListener, stopScan } from 'munim-wifi'
const monitorSignalStrength = (targetSSID: string) => {
const rssiHistory: number[] = []
const unsubscribe = addNetworkFoundListener((network) => {
if (network.ssid === targetSSID) {
rssiHistory.push(network.rssi)
console.log(`Current RSSI: ${network.rssi} dBm`)
console.log(`Average RSSI: ${rssiHistory.reduce((a, b) => a + b, 0) / rssiHistory.length} dBm`)
}
})
startScan()
// Stop after 30 seconds
setTimeout(() => {
stopScan()
unsubscribe()
}, 30000)
}-
Permission Denied: Ensure you have the necessary location permissions in your app. On Android 6.0+, location permission is required for Wi-Fi scanning.
-
No Networks Found:
- Verify Wi-Fi is enabled on the device
- Check that location permissions are granted
- On iOS, ensure location services are enabled in Settings
-
Scan Timeout: Increase the timeout value in scan options or check network connectivity
-
Empty Results: Make sure you've called
scanNetworks()orstartScan()before callinggetSSIDs()or other getter methods
-
Development Build Required: This library requires a development build in Expo. Use
npx expo run:iosornpx expo run:android -
Permissions Not Working: Make sure you've added the permissions to your
app.jsonas shown in the setup section -
Build Errors: Ensure you're using Expo SDK 50+ and have the latest Expo CLI
-
Nitro Modules: Make sure you have
react-native-nitro-modulesinstalled and configured
Android:
- Requires
ACCESS_FINE_LOCATIONorACCESS_COARSE_LOCATIONpermission - Wi-Fi scanning may be limited on some devices
- Background scanning has restrictions on Android 8.0+
iOS:
- Requires location permission for Wi-Fi scanning
- CoreWLAN framework is used for scanning
- Some network information may be limited for privacy reasons
We welcome contributions! Please see our Contributing Guide for details on how to submit pull requests, report issues, and contribute to the project.
This project is licensed under the MIT License - see the LICENSE file for details.
