React Native BLE Device Scanner UI Kit
BLE discovery is noisy and asynchronous. The scanner's job is turning a chaotic stream of advertisements into a clean, pickable list.
TL;DR
A BLE device scanner turns the noisy stream of Bluetooth Low Energy advertisements into a clean, pickable list, and it needs a development build (BLE is native; react-native-ble-plx at 238,762 weekly downloads is the standard library), not Expo Go. The craft is handling BLE's realities: deduplicate by device ID (a device advertises many times a second), smooth and sort by signal strength so the closest device floats up, age out stale entries, and filter by service UUID. The hard part is the permission-and-power gauntlet: distinguish Bluetooth-off, permission-denied, and no-devices-nearby explicitly, never one blank list for all three. Tapping hands off to a connection with its own honest states. A free VP0 design supplies the scan and connection screens.
What does a BLE device scanner actually show?
The list of Bluetooth Low Energy devices around the user, updating live as they appear, with the signal strength and identity needed to pick the right one. A BLE scanner is the entry screen of every connected-hardware app, a smart lock, a fitness band, a sensor, a printer, and it is harder than it looks because BLE discovery is noisy, asynchronous, and full of devices the user does not care about. The scanner’s job is turning a chaotic stream of advertisement packets into a clean, pickable list.
The honest framing first: this needs a development build, not Expo Go, because BLE is native code, and the standard library is react-native-ble-plx (238,762 weekly downloads), which handles the platform BLE stack. The scanner is the UI on top of it, and the craft is in handling the realities BLE throws at you: duplicate advertisements, signal flicker, devices appearing and vanishing, and the permission and power-state gauntlet iOS puts in front of any scan.
How does live scanning actually work?
As a managed stream with deduplication and sorting, not a raw dump:
| Reality | What the scanner does | Why |
|---|---|---|
| Devices re-advertise constantly | Deduplicate by device ID | One device, one row, not 50 |
| Signal flickers (RSSI) | Smooth and sort by signal | Closer devices float to the top |
| Devices vanish | Age out stale entries | A device out of range should drop off |
| Most devices are noise | Filter by service UUID or name | Show only the devices your app cares about |
| Identity is cryptic | Resolve names, show device type | A UUID means nothing to a user |
Deduplication is the first real problem: a device advertises many times a second, so naive rendering shows the same lock 50 times, which means the scanner tracks devices by identifier and updates one row per device rather than appending every packet, the same dedup discipline as any continuous-capture scanner. Signal strength (RSSI) is how the user finds the right device (the closest one is usually theirs), so smoothing the flickery RSSI and sorting by it puts the intended device at the top. And filtering by service UUID is what turns a list of every Bluetooth thing in the building into the few your app can actually connect to.
Why is the permission and state gauntlet the hard part?
Because iOS will not let you scan until everything is exactly right, and each failure looks different. Before a scan returns anything, the app must handle: Bluetooth being off (prompt to enable, do not just show an empty list), the Core Bluetooth authorization not yet granted (request it, explain why), and the power-state transitions (Bluetooth toggling mid-session). An empty scanner is ambiguous, no devices nearby, or permission denied, or Bluetooth off, so the honest UI distinguishes these states explicitly rather than showing the same blank list for all three, which is the most common BLE-scanner failure.
The scan also costs battery and should be bounded: scan while the screen is open, stop when it is not, and show a clear scanning indicator so the user knows it is live. This is the same render-the-real-state honesty as any sensor UI, applied to a permission-and-power model that is genuinely fiddly, the same Core Bluetooth state-machine care as the CoreBluetooth templates.
What completes the scanner-to-connection flow?
The handoff. The scanner is the first step; tapping a device initiates a connection, which has its own states (connecting, connected, failed, disconnected) the UI must show honestly, because connection is where BLE most often disappoints (a device in range that will not pair). A remembered-devices section (reconnect to a previously-paired device fast) and clear per-device detail (name, signal, type) round it out. And honest errors: a connection that fails gets a specific, recoverable message, not a generic spinner that never resolves.
The screens, the live scan list, the device row with signal, the connection states, the remembered devices, come as a free VP0 design, so an agent builds the ble-plx scan-and-dedup logic onto a UI already shaped for live discovery, signal sorting, and the permission states rather than a raw device dump.
Key takeaways: a BLE device scanner
- It needs a dev build, not Expo Go: BLE is native; react-native-ble-plx is the standard library.
- Turn the packet stream into a clean list: deduplicate by device ID, smooth and sort by signal, age out stale entries, filter by service UUID.
- The permission and power gauntlet is the hard part: distinguish Bluetooth-off, permission-denied, and no-devices, never one blank list for all three.
- Signal strength is how users pick: smoothing flickery RSSI and sorting by it floats the intended device to the top.
- The scan is step one: tapping hands off to a connection with its own honest states, plus a fast reconnect to remembered devices.
Frequently asked questions
How do I build a BLE device scanner in React Native? Use react-native-ble-plx in a development build (not Expo Go), and turn the advertisement stream into a clean list: deduplicate by device ID, smooth and sort by RSSI, age out stale devices, and filter by service UUID. Handle Bluetooth-off and permission states explicitly. A free VP0 design supplies the scan list and connection screens.
Why can’t I build a BLE scanner in Expo Go? Because BLE is native code that Expo Go does not bundle, so you need a development build that includes react-native-ble-plx (or the BLE library). The scanner UI runs on top of that native library, and Expo Go’s fixed module set cannot provide the Bluetooth stack a real scanner requires.
Why does my BLE scanner show the same device many times? Because BLE devices advertise many times a second and naive rendering appends every packet. Deduplicate by the device identifier and update one row per device rather than adding a row per advertisement, so a single lock shows as one entry whose signal updates, not fifty entries.
How should the scanner handle an empty list? By distinguishing the three causes explicitly: Bluetooth is off (prompt to enable), permission is not granted (request it with a reason), or no devices are nearby (a genuine empty state). Showing the same blank list for all three is the most common BLE-scanner failure, since the user cannot tell what to fix.
How do users find the right device in a BLE scan? By signal strength: the closest device is usually theirs, so smooth the flickery RSSI and sort by it to float the intended device to the top, and show the signal per row. Filtering by service UUID also helps, turning a list of every Bluetooth thing nearby into the few devices your app can actually connect to.
Questions from the community
How do I build a BLE device scanner in React Native?
Use react-native-ble-plx in a development build (not Expo Go), and turn the advertisement stream into a clean list: deduplicate by device ID, smooth and sort by RSSI, age out stale devices, and filter by service UUID. Handle Bluetooth-off and permission states explicitly. A free VP0 design supplies the scan list and connection screens.
Why can't I build a BLE scanner in Expo Go?
Because BLE is native code that Expo Go does not bundle, so you need a development build that includes react-native-ble-plx (or the BLE library). The scanner UI runs on top of that native library, and Expo Go's fixed module set cannot provide the Bluetooth stack a real scanner requires.
Why does my BLE scanner show the same device many times?
Because BLE devices advertise many times a second and naive rendering appends every packet. Deduplicate by the device identifier and update one row per device rather than adding a row per advertisement, so a single lock shows as one entry whose signal updates, not fifty entries.
How should a BLE scanner handle an empty list?
By distinguishing the three causes explicitly: Bluetooth is off (prompt to enable), permission is not granted (request it with a reason), or no devices are nearby (a genuine empty state). Showing the same blank list for all three is the most common BLE-scanner failure, since the user cannot tell what to fix.
How do users find the right device in a BLE scan?
By signal strength: the closest device is usually theirs, so smooth the flickery RSSI and sort by it to float the intended device to the top, and show the signal per row. Filtering by service UUID also helps, turning a list of every Bluetooth thing nearby into the few devices your app can actually connect to.
Part of the Native Hardware, Sensors & Device Features hub. Browse all VP0 topics →
Keep reading
Smart Pet Feeder Schedule UI in React Native: The Build
The feeder runs the schedule, the app just edits and mirrors it: pending-until-ack writes, a last-fed home screen, guarded Feed now, and honest offline state.
Bluetooth Printer Receipt UI in React Native: ESC/POS
Print receipts from React Native over Bluetooth: ESC/POS as the language, pairing that survives shifts, character-grid layout, and honest printer states.
Audio Waveform Recorder UI in React Native
Build a voice recorder UI in React Native: a live waveform, record and pause, and playback, from a free VP0 design. With a real, metered waveform.
IoT Smart-Home Dashboard in React Native (Free UI)
Build a smart-home dashboard in React Native: device tiles, room grouping, and quick toggles, from a free VP0 design. Prefer HomeKit and Matter.
React Native WebRTC Video Call UI Kit (Free Design)
Build a video call UI in React Native with WebRTC: local and remote video, mute and camera controls, and call states, from a free VP0 design.
Spatial Audio Soundscape UI in React Native
Build a spatial audio soundscape app in React Native: layered ambient sounds placed in 3D space, a mixer, and background playback, from a free VP0 design.