Installation
MacTools BLE Inspector is a native macOS app built with Swift and Tauri on top of CoreBluetooth. It runs natively on Apple Silicon and Intel Macs — no Rosetta, no Parallels, no Android Studio, no nRF Connect install failures. One-time purchase, no subscription.
Download
- Direct purchase: buy direct ($9.99 one-time) — you receive a download link by email
- Product page: /ble-inspector/
System Requirements
| Requirement | Minimum |
|---|---|
| macOS | 12 Monterey or newer (Apple Silicon & Intel) |
| Bluetooth | Built-in Bluetooth 4.0+ (all Macs since 2012). External BT dongles generally unsupported — CoreBluetooth requires the internal radio. |
| Privacy permission | On first launch, grant Bluetooth access when macOS prompts. Without it, scanning returns nothing. |
| For background scanning | Location may be required if the app needs to continue scanning while backgrounded (macOS policy). |
First Launch
If you downloaded the direct build outside the App Store, macOS Gatekeeper may block the unsigned binary on first run. Right-click the app, choose Open, then confirm. This is only required once.
Quick Start
1. Scan for BLE peripherals (1 minute)
This is the most common path — finding the BLE device you're developing against (an ESP32, an nRF52 dev kit, a sensor beacon, a fitness tracker).
- Open the app and click Start Scanning (or press
⌘R). - The peripheral list fills with every advertiser in range, showing name, MAC-ish UUID, RSSI, and advertised service UUIDs.
- Sort by RSSI to bring the closest devices to the top. Your target is usually the strongest signal.
- Click a peripheral to open its detail view.
If the list stays empty, jump to Troubleshooting — the most frequent cause is a denied Bluetooth permission or the peripheral not advertising.
2. Connect and browse the GATT hierarchy
- Click Connect on the chosen peripheral. The app performs a connection and service discovery.
- The GATT tree appears: Services (128-bit UUIDs) expand into Characteristics, which expand into Descriptors.
- Standard services show their decoded name (e.g.
Device Information (0x180A)) alongside the raw UUID.
3. Read and write a characteristic
- Find a characteristic with the
Readproperty. Click Read — the value and its length appear in hex and ASCII. - For a writable characteristic (
Writeproperty), click Write, enter the value (hex or text), choose write-with-response or write-without-response, and send. - The read-back confirms the write took.
4. Subscribe to notifications
- For a characteristic with the
Notifyproperty, enable the Client Characteristic Configuration Descriptor (CCCD) by clicking Subscribe. - Live values stream into the characteristic's value log as the peripheral pushes them — typically every second for sensor data.
- Click Unsubscribe to stop; Disconnect to tear down.
Configuration
Scan Settings
| Parameter | Options |
|---|---|
| Scan mode | Passive (listen only, lower power, misses some data) / Active (requests scan-response data, default) |
| Service filter | Only show peripherals advertising a specific 16-bit or 128-bit service UUID — essential in a crowded 2.4 GHz environment |
| RSSI floor | Hide peripherals weaker than -90 dBm (default) to declutter the list |
| Duplicate filtering | Show each peripheral once (update RSSI in place) vs. log every advertisement packet |
UUID Types
BLE UUIDs are either 16-bit (a registered short that maps to a 128-bit base) or full 128-bit. The app decodes the Bluetooth SIG assigned numbers and shows both forms.
| UUID | Name | Where You'll See It |
|---|---|---|
| 0x180A | Device Information | Almost every peripheral — manufacturer name, model, firmware |
| 0x180F | Battery Service | Battery level percentage |
| 0x2A00 | Device Name | The friendly name advertised |
| 0x2A29 | Manufacturer Name String | Under Device Information |
| 0x2A37 | Heart Rate Measurement | Heart-rate belt / fitness devices |
| 0x2902 | CCCD | On every notifiable/indicate characteristic — the subscribe toggle |
| custom 128-bit | Vendor-defined | Your firmware's custom service — not decoded, shown as the raw UUID |
Characteristic Properties
| Property | Meaning |
|---|---|
| Read | Supports read requests |
| Write | Supports write with response (acknowledged) |
| Write Without Response | Supports fire-and-forget write (faster, unacknowledged) |
| Notify | Server pushes updates; no acknowledgment (default for sensor data) |
| Indicate | Server pushes updates with acknowledgment (more reliable, slightly slower) |
| Broadcast | Can be included in advertising data |
| Authenticated Signed Write | Write requires a signed (paired) connection |
Connection Parameters
Once connected, the peripheral and Mac negotiate connection parameters: interval, slave latency, supervision timeout. The app displays the negotiated values. Faster intervals (e.g. 7.5–15 ms) mean lower latency and higher power draw; slower intervals (100–1000 ms) save battery. The peripheral requests a set; the Mac (central) accepts or adjusts.
| Parameter | Typical Range |
|---|---|
| Connection interval | 7.5 ms – 4 s (multiples of 1.25 ms) |
| Slave latency | 0–499 (slave may skip this many intervals) |
| Supervision timeout | 100 ms – 32 s (link assumed dead after this idle) |
| MTU | 23 (default) up to 247 bytes after MTU exchange |
Key Features
Real-time advertising scanner
The scanner shows every advertisement with RSSI trend, advertised service UUIDs, manufacturer-specific data, and TX power. Filter by service UUID to isolate your device in a busy trade-show floor or a lab full of beacons.
Full GATT hierarchy browser
Services → Characteristics → Descriptors, with the SIG-assigned names decoded inline. For custom 128-bit UUIDs, you can annotate each with a friendly name in a saved profile, so your next session shows "Motor Speed" instead of a hex string.
Read, write, notify, indicate
Every GATT operation is one click. Notifications and indications stream into a per-characteristic log with timestamps. Write supports both write-with-response (reliable) and write-without-response (fast) — critical for throughput-sensitive firmware testing.
Payload decoder with common formats
Raw bytes are shown in hex and ASCII, and you can apply a decoder: UTF-8 string, little/big-endian integer, IEEE 754 float, or a custom struct layout. Decode a 4-byte temperature payload as a float once, and every subsequent notification renders in engineering units.
MTU exchange and connection tuning
Request a larger MTU after connecting to boost throughput (useful for OTA firmware updates over BLE). The negotiated MTU and connection parameters are displayed live, so you can confirm the peripheral honored your request.
Advertising packet capture
For commissioning and reverse-engineering, the app logs every advertisement packet — raw PDU, type (ADV_IND, ADV_NONCONN_IND, SCAN_RSP), and the manufacturer-data payload. Export the log to dissect a vendor's beacon format or debug intermittent advertising.
Troubleshooting
Common BLE failure modes
| Symptom | Likely Cause |
|---|---|
| Scan returns nothing | Bluetooth permission denied, or radio off, or no peripherals advertising |
| Peripheral in list but won't connect | Out of range, peripheral is bonded/paired-only, or central slot exhausted |
| Connects then disconnects in ~30 s | Supervision timeout — link dropped by interference or the peripheral rejected the connection parameters |
| Read returns "Not supported" | The characteristic lacks the Read property — check the properties bitmask |
| Write returns "Invalid handle" or fails silently | Wrong write type (write-without-response on a write-with-response-only characteristic, or vice versa) |
| Notifications never arrive | CCCD not enabled, or the characteristic supports Indicate (not Notify) — the subscribe call must match |
Scan returns empty (Bluetooth permission)
Symptom: Scan is running, the list stays empty, known BLE devices are nearby.
Fix: macOS denied Bluetooth access. Open System Settings → Privacy & Security → Bluetooth and confirm the app is toggled on. If it's not listed, click the + and re-add it, or re-launch the app to re-trigger the prompt. Also confirm the Mac's Bluetooth radio is on (menu bar icon).
Peripheral seen in scan but connection fails
Symptom: Clicking Connect shows a spinner, then fails or silently disconnects.
Fix: Three common causes: (1) the peripheral is now out of range (BLE advertising ≠ connectable reliably past 10 m). Move closer. (2) The peripheral is bonded and rejects non-bonded centrals — pair first. (3) The Mac's central already holds its max concurrent connections (typically 7–12). Disconnect stale peripherals and retry.
Notifies don't arrive (CCCD / property mismatch)
Symptom: You subscribed but no values stream.
Fix: Check the characteristic's properties. If it has Indicate but not Notify, the subscribe action must request Indicate — the app handles this automatically when you click Subscribe, but a manual CCCD write to the wrong bit (0x0001 Notify vs 0x0002 Indicate) produces silence. Also confirm the CCCD (0x2902) descriptor exists; without it, the characteristic can't be subscribed.
Disconnects after 30 seconds (supervision timeout)
Symptom: Connection holds briefly, then drops.
Fix: The supervision timeout lapsed because no packets were exchanged in the window — usually RF interference or the peripheral sleeping. Confirm the peripheral is awake and transmitting. If you control the firmware, widen the connection interval or raise slave latency so the link survives brief quiet periods.
Write rejected (write-with-response vs without-response)
Symptom: Write fails or returns an error on a known-writable characteristic.
Fix: The characteristic accepts only one write type, not both. Check the properties: if only Write is set, use write-with-response; if only Write Without Response, use the fire-and-forget path. Sending the wrong type returns an error or silently drops the byte. The app selects based on the properties bitmask automatically, but a manual override will trip this.
nRF Connect comparison / install issues
The de facto reference tool, nRF Connect for Desktop, has well-documented install failures on macOS (the BLE module fails with "Failed to get the library" errors on Apple Silicon). This app covers the same scan + connect + GATT browse + read/write workflow natively, without the JRE/JNI dependency chain that breaks nRF Connect. If you're migrating from nRF Connect, the GATT tree and characteristic-property semantics map 1:1.
Support
- Email: support@voltrus.id
- Product page: /ble-inspector/
When reporting a connection or GATT issue, attach the advertising/gatt log export (with any device-identifying UUIDs redacted), the peripheral's model/firmware, and the characteristic UUID + properties you were operating on.