Find your accessory with Bluetooth Channel Sounding
Use Bluetooth Channel Sounding on iOS 27 to measure accessory distance with Core Bluetooth, or distance and direction with Nearby Interaction.
TL;DR
- Bluetooth Channel Sounding measures distance to paired, connected Bluetooth accessories more accurately than RSSI when the accessory does not include Ultra Wideband.
- Use Core Bluetooth when the app only needs distance; start a channel sounding session on a connected CBPeripheral and receive per-procedure distance results.
- Use Nearby Interaction when the app needs distance and direction; pass the Core Bluetooth peripheral identifier into NINearbyAccessoryConfiguration and enable Camera Assistance for direction.
- Accessory hardware must support Bluetooth 6.3, inline PCT, phase-based ranging mode-0 and mode-2, and T_FCS of at least 100 µs.
What Bluetooth Channel Sounding adds
Bluetooth Channel Sounding lets an iPhone measure distance to a nearby Bluetooth accessory by sending tones to a connected accessory and measuring reflected tones across the 2.4 GHz band. In the Channel Sounding roles, iPhone is the initiator and the accessory is the reflector.
This is positioned as the best option for distance-aware experiences when the accessory only has a Bluetooth chipset. For the highest accuracy, Apple still points developers toward Ultra Wideband accessories with Nearby Interaction.
- Use Channel Sounding instead of RSSI when the app benefits from measured distance rather than rough signal-strength estimation.
- A single distance measurement is called a procedure; iOS repeatedly performs procedures during a session.
- The accessory should already be paired and set up with AccessorySetupKit and connected through Core Bluetooth before starting.
Distance with Core Bluetooth
Core Bluetooth is the direct path when the app only needs distance. Check support on the local iOS device, then start a Channel Sounding session on a connected CBPeripheral. iOS performs repeated procedures and reports measured distance in meters through the peripheral delegate.
Cancel the session when the app no longer needs measurements. A completion delegate callback reports that the session has ended.
- Check CBCentralManager.supportsFeatures(.channelSounding) on iOS 27 or later.
- Call startChannelSoundingSession(_:) on a connected CBPeripheral using CBChannelSoundingSessionConfiguration(role: .initiator).
- Read distance from CBChannelSoundingProcedureResults.distance in the delegate callback.
- Call cancelChannelSoundingSession when finished; observe didCompleteChannelSoundingSession for completion.
Start and receive Core Bluetooth Channel Sounding results
Shows the Core Bluetooth flow: check feature support, start a session on a connected peripheral, and receive distance results.
import CoreBluetooth
func isChannelSoundingSupported() -> Bool {
guard centralManager.state == .poweredOn else { return false }
if #available(iOS 27.0, *) {
return CBCentralManager.supportsFeatures(.channelSounding)
}
return false
}
func startChannelSounding(_ peripheral: CBPeripheral) {
guard peripheral.isConnected else { return }
if #available(iOS 27.0, *) {
let config = CBChannelSoundingSessionConfiguration(role: .initiator)
peripheral.startChannelSoundingSession(config)
}
}
func peripheral(_ peripheral: CBPeripheral,
didReceive results: CBChannelSoundingProcedureResults?,
error: Error?) {
guard let results else { return }
let distance = results.distance
// Use distance in meters.
}Cancel a Core Bluetooth Channel Sounding session
End the session explicitly and handle the completion callback.
func cancelChannelSounding(_ peripheral: CBPeripheral) {
guard peripheral.isConnected else { return }
if #available(iOS 27.0, *) {
peripheral.cancelChannelSoundingSession(config)
}
}
func peripheral(_ peripheral: CBPeripheral,
didCompleteChannelSoundingSession error: Error?) {
// Session is complete.
}Distance and direction with Nearby Interaction
Nearby Interaction is the recommended API when the app needs both distance and direction to a Bluetooth accessory. The configuration links the Nearby Interaction session to the Core Bluetooth peripheral by passing the peripheral.identifier as the bluetoothChannelSoundingIdentifier.
Direction output requires Camera Assistance. If the app knows whether the accessory is moving or stationary, pass that motion state to Nearby Interaction to improve direction estimates.
- Check NISession.deviceCapabilities.supportsBluetoothChannelSounding before creating the configuration.
- Create NINearbyAccessoryConfiguration with bluetoothChannelSoundingIdentifier: peripheral.identifier.
- Enable config.isCameraAssistanceEnabled when NISession.deviceCapabilities.supportsCameraAssistance and direction is needed.
- Run an NISession with the accessory configuration and receive NINearbyObject updates containing optional distance and horizontalAngle values.
Configure a Nearby Interaction Channel Sounding session
Creates the Nearby Interaction accessory configuration using the Core Bluetooth peripheral identifier and enables Camera Assistance when available.
import CoreBluetooth
import NearbyInteraction
func makeChannelSoundingConfiguration(for peripheral: CBPeripheral) -> NINearbyAccessoryConfiguration? {
if #available(iOS 27.0, *) {
guard NISession.deviceCapabilities.supportsBluetoothChannelSounding else { return nil }
let config = NINearbyAccessoryConfiguration(
bluetoothChannelSoundingIdentifier: peripheral.identifier,
previousChannelSoundingIdentifier: nil
)
if NISession.deviceCapabilities.supportsCameraAssistance {
config.isCameraAssistanceEnabled = true
}
return config
}
return nil
}Run the session and consume Nearby Interaction updates
Runs the NISession, optionally supplies accessory motion state, and reads distance and direction from Nearby Interaction updates.
let session = NISession()
session.delegate = self
session.run(config)
func updateAccessoryMotionState(_ isMoving: Bool, object: NINearbyObject) {
let motionState: NIMotionActivityState = isMoving ? .moving : .stationary
session.updateMotionState(motionState, forObjectWithToken: object.discoveryToken)
}
func session(_ session: NISession, didUpdate nearbyObjects: [NINearbyObject]) {
guard let object = nearbyObjects.first else { return }
if let distance = object.distance {
// Use distance.
}
if let direction = object.horizontalAngle {
// Use horizontal angle.
}
}Runtime behavior and platform constraints
Nearby Interaction fuses raw Bluetooth Channel Sounding measurements with camera inputs when Camera Assistance is enabled. iOS also filters outliers and smooths results to improve the user experience.
Both distance and direction should be treated as optional. A distance value can be nil if a Channel Sounding measurement fails, and direction also depends on the necessary inputs being available.
- Channel Sounding APIs are described for iOS 27.
- Channel Sounding is available on iPhones with the N1 chip.
- Use Channel Sounding while the app is in the foreground; iOS pauses the session when the app moves to the background.
- iOS may reduce Channel Sounding measurement frequency when other Bluetooth or Wi-Fi activity increases.
Accessory hardware requirements
Accessory-side support is required for Channel Sounding to work well with iOS. The accessory acts as the reflector and must implement the Bluetooth features and timing needed by iOS phase-based ranging.
- Support Bluetooth 6.3.
- Support the inline PCT feature.
- Support phase-based ranging mode-0 and mode-2 as defined by the Bluetooth specification.
- Support T_FCS interspace timing between tones of at least 100 µs.
Resources
Related Sessions
What’s new in Shortcuts
Build better Shortcuts integrations with new automations, Use Model transcript debugging, and synced Storage for app data and App Entities.
Power and Performance Group Lab
Online WWDC26 group lab for discussing power and performance announcements with Apple engineers and designers.