An ITMS-90683 rejection that names Bluetooth means your build can reach the Bluetooth APIs, but Info.plist has no usage string explaining why. Often you did not knowingly add Bluetooth at all: a library an AI agent wired in references it for you. The fix is one Info.plist key with a clear reason, and a rebuild. Here is which key, why the rejection appears, and how to add it across stacks.
Short answer
ITMS-90683 naming Bluetooth means your binary references the CoreBluetooth APIs without a Bluetooth usage string in Info.plist. Add NSBluetoothAlwaysUsageDescription, the key for iOS 13 and later, with a specific reason the user reads in the permission prompt, and add NSBluetoothPeripheralUsageDescription only if you still support iOS 12 or earlier. A bundled SDK can reference Bluetooth even when your own code does not, which is why agent-generated integrations get flagged for a feature nobody chose. Because the key lives in Info.plist, the fix ships in a new build.
What you should know
- It is a binary check: ITMS-90683 fires at upload when the build references the Bluetooth APIs.
- NSBluetoothAlwaysUsageDescription is the key: it covers Bluetooth on iOS 13 and later.
- The peripheral key is legacy: NSBluetoothPeripheralUsageDescription only matters for iOS 12 and earlier.
- An SDK can trigger it: a library that references CoreBluetooth requires the key even if your code does not call it.
- The fix needs a new build: Info.plist is compiled into the binary, so a metadata edit cannot resolve it.
Which Bluetooth key do you actually need?
In almost all cases, NSBluetoothAlwaysUsageDescription. Apple consolidated Bluetooth permission into that single key starting with iOS 13, and it covers both connecting to devices and acting as a peripheral. The older NSBluetoothPeripheralUsageDescription was used by iOS 12 and earlier for advertising as a peripheral, so you only add it if your deployment target still includes those versions. The table sorts it out.
| Key | When you need it |
|---|---|
| NSBluetoothAlwaysUsageDescription | The build can use Bluetooth on iOS 13 or later |
| NSBluetoothPeripheralUsageDescription | Only if you still support iOS 12 or earlier |
If your minimum supported version is iOS 13 or higher, the Always key alone is enough, and adding the peripheral key does no harm but is not required. It is worth checking your project's deployment target before adding keys, because shipping the legacy key on a modern app is a small sign of copied configuration rather than a real iOS 12 requirement, and reviewers occasionally ask why an app declares access it does not use.
Why is my app flagged for Bluetooth when I don't use it?
Because the requirement is triggered by the API the binary can reach, not the feature you built. A third-party SDK compiled into your app, a BLE device library, a beacon or proximity SDK, a printer or hardware integration, can reference CoreBluetooth, and Apple's static check sees that reference at the binary level. The same guidance that applies to other permissions applies here: an external library may reference these APIs even when your app does not, and a purpose string is still required. This is common in agent-generated code, where the model adds an integration that pulls in a Bluetooth-capable dependency, and the matching Info.plist key never gets added. The tell is that the rejection names Bluetooth even though there is no Bluetooth feature anywhere in your app's interface, which means the reference is coming from a dependency rather than from anything you wrote.
How do you add the key, by stack?
Put the key and a human-readable reason into the final Info.plist, then rebuild. In a native Xcode project, add it directly:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to connect to your nearby device.</string>
In an Expo project, declare it under ios.infoPlist in app.json so Expo writes it during prebuild:
{
"expo": {
"ios": {
"infoPlist": {
"NSBluetoothAlwaysUsageDescription": "This app uses Bluetooth to connect to your nearby device."
}
}
}
}
In FlutterFlow, Capacitor, or a similar builder, enable the Bluetooth permission in the project settings and write a clear description, and the builder injects the key into Info.plist when it builds the iOS bundle.
Does fixing it need a new build or a metadata reply?
A new build. Info.plist is compiled into the app bundle, so the only way to add a usage string that App Store Connect validates is to rebuild and re-upload, which returns the submission to review. A metadata reply cannot clear ITMS-90683, because the missing data lives inside the binary rather than in the App Store listing. Batch this with any other binary-level fixes so you do not restart review more than once.
What to watch out for
The first trap is a vague string. A description like "This app uses Bluetooth" can clear ITMS-90683 and then draw a separate rejection under App Store Review Guideline 5.1.1, which asks for a specific, user-facing reason, so name what the Bluetooth connection does for the user. The second is declaring Bluetooth you do not actually need; the safer move is to find which SDK pulled in CoreBluetooth and decide whether you want that dependency at all. Mapping that by hand is error-prone, which is the case for an external read of the build. A pre-submission scan such as PTKD.com (https://ptkd.com) reads the compiled APK, AAB, or IPA and reports the permissions and SDKs it requests against OWASP MASVS, so you can see the Bluetooth reference and its source before the upload flags it. Knowing the source also lets you make a real decision: keep the SDK and declare Bluetooth honestly, or remove the dependency if the capability is incidental and unwanted.
What to take away
- ITMS-90683 naming Bluetooth means a CoreBluetooth reference in your binary has no Info.plist usage string.
- Add NSBluetoothAlwaysUsageDescription for iOS 13 and later, and the peripheral key only if you still support iOS 12.
- The trigger is the API the build links, so a bundled SDK can require the key for Bluetooth you never knowingly used, which is common in agent-generated code.
- Write a specific reason, rebuild since the key is in the binary, and scan the build with a pre-submission scan such as PTKD.com to see which SDK requested Bluetooth.



