Privacy

    How do I fix ITMS-90683 missing Bluetooth Purpose String?

    An App Store Connect ITMS-90683 missing Bluetooth purpose string rejection in 2026 next to an Xcode Info.plist with the NSBluetoothAlwaysUsageDescription key being added, and a third-party SDK shown as the source of the CoreBluetooth reference

    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.

    KeyWhen you need it
    NSBluetoothAlwaysUsageDescriptionThe build can use Bluetooth on iOS 13 or later
    NSBluetoothPeripheralUsageDescriptionOnly 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.
    • #itms-90683
    • #bluetooth
    • #purpose-string
    • #nsbluetoothalwaysusagedescription
    • #info-plist
    • #corebluetooth
    • #ios

    Frequently asked questions

    What does ITMS-90683 for Bluetooth mean?
    It is a binary-validation rejection that means your app references the CoreBluetooth APIs without a Bluetooth usage-description key in Info.plist. It fires during upload or processing, before a human reviewer sees the app. The fix is to add NSBluetoothAlwaysUsageDescription with a clear reason and upload a new build, because the missing string is part of the binary, not the App Store listing.
    Which Bluetooth key do I add, Always or Peripheral?
    Add NSBluetoothAlwaysUsageDescription, which Apple uses for Bluetooth on iOS 13 and later and which covers both connecting to devices and acting as a peripheral. Add NSBluetoothPeripheralUsageDescription only if your deployment target still includes iOS 12 or earlier, where that older key was used. If your minimum version is iOS 13 or higher, the Always key on its own is enough.
    Why is my app flagged for Bluetooth when it has no Bluetooth feature?
    A third-party SDK compiled into your binary most likely references CoreBluetooth, such as a BLE device, beacon, or hardware library. App Review's static check sees that reference at the binary level, so it requires the purpose string even though your own code never opens Bluetooth. This is common in agent-generated code, where an added integration pulls in a Bluetooth-capable dependency without the matching Info.plist key.
    Should I add both Bluetooth keys to be safe?
    Only if you still support iOS 12 or earlier. On iOS 13 and later, NSBluetoothAlwaysUsageDescription is the key Apple uses, and the peripheral key is legacy. Adding the peripheral key when your minimum is iOS 13 does no harm but is unnecessary. The better safety move is to identify which SDK requires Bluetooth and confirm you actually want that dependency rather than declaring access you do not need.
    Does fixing the Bluetooth purpose string require a new build?
    Yes. Info.plist is compiled into the app bundle, so a usage-description string can only be added by rebuilding and re-uploading, which returns the submission to review. A metadata reply cannot resolve ITMS-90683, because the missing data is inside the binary. Batch the change with any other binary fixes so you restart review only once.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free