App Store Compliance
ITMS-90683: Missing purpose string in Info.plist — the fix
App Store Connect rejected your build with ITMS-90683. Here's exactly which Info.plist key is missing, why, and the precise usage-description string that resolves it.
You uploaded a build and got the processing email with this:
ITMS-90683: Missing purpose string in Info.plist — Your app's code
references one or more APIs that access sensitive user data. The app's
Info.plist file should contain a NSCameraUsageDescription key with a
user-facing purpose string explaining clearly and completely why your
app needs the data. Starting Spring 2019, all apps submitted to the
App Store that access user data are required to include a purpose
string.
The key name (NSCameraUsageDescription above) varies — it could be NSPhotoLibraryUsageDescription, NSLocationWhenInUseUsageDescription, NSMicrophoneUsageDescription, NSContactsUsageDescription, or any other protected-resource key. The fix is always the same shape.
This is the systematic walkthrough: what triggers ITMS-90683, how to find which key you’re missing, and the exact string to add.
For the full submission picture, see every URL and file Apple requires for an iOS App Store submission.
What ITMS-90683 actually means
iOS gates ~30 categories of sensitive data behind a runtime permission prompt. Before iOS shows that prompt, it reads a human-readable explanation from your app’s Info.plist — the “purpose string” or “usage description.” If your binary calls an API that touches one of those resources but the corresponding Info.plist key is missing, App Store Connect rejects the build at processing time with ITMS-90683.
Crucially: it’s triggered by the API being present in your binary, not by your app actually calling it at runtime. A third-party SDK that links AVCaptureDevice triggers the camera requirement even if your app never opens the camera. This is why teams get ITMS-90683 for permissions they “don’t use.”
This is enforced under App Store Review Guideline 5.1.1(ii) — Permission.
Step 1: Identify the exact missing key
The error message names the key (NSCameraUsageDescription in the example). The most common ones:
| Info.plist key | Triggered by |
|---|---|
NSCameraUsageDescription |
AVCaptureDevice, UIImagePickerController camera source |
NSPhotoLibraryUsageDescription |
PHPhotoLibrary, photo picker with write access |
NSPhotoLibraryAddUsageDescription |
Saving to the photo library |
NSMicrophoneUsageDescription |
AVAudioRecorder, audio capture |
NSLocationWhenInUseUsageDescription |
CLLocationManager |
NSContactsUsageDescription |
CNContactStore |
NSCalendarsUsageDescription |
EKEventStore |
NSBluetoothAlwaysUsageDescription |
CBCentralManager |
NSUserTrackingUsageDescription |
ATTrackingManager |
NSLocalNetworkUsageDescription |
Bonjour / local network sockets |
If the error names a key you don’t recognize, it’s almost certainly from a dependency. Find it:
# Search your built .app bundle for the symbol that triggers the requirement
# (example: camera). Run against the .app inside your archive.
nm -u "YourApp.app/YourApp" | grep -i "AVCaptureDevice"
# Or grep your Pods / SPM checkouts for the usage-description-triggering APIs
grep -rl "AVCaptureDevice\|CLLocationManager\|CNContactStore" Pods/ 2>/dev/null
Step 2: Add the purpose string
In Xcode, open your target’s Info.plist (or the Info tab of the target settings) and add the key with a specific, honest value.
The raw Info.plist XML:
<key>NSCameraUsageDescription</key>
<string>Capybara Cam uses the camera to let you take and attach photos to a sighting report.</string>
Or in a modern Xcode project that uses the generated Info.plist (build settings → Info), add it under “Custom iOS Target Properties.”
Apple’s reference for each key is in the Information Property List documentation (swap the last path component for whichever key you need).
Step 3: Write a string that won’t get a second rejection
ITMS-90683 only checks that the key exists. But App Review (a human) reads the string and rejects under 5.1.1(ii) if it’s vague or dishonest. The bar:
Too vague (will get a manual rejection even after ITMS-90683 clears):
This app needs access to your camera.
Specific and honest (passes):
Capybara Cam uses the camera to let you photograph a sighting and
attach it to your field report. Photos stay on your device unless you
choose to upload them.
Rules for the string:
- Name the concrete feature the permission enables.
- If the data leaves the device, say so.
- Don’t claim a benign purpose if an SDK uses it for something broader — that’s a 5.1.1(ii) misrepresentation.
- One to two sentences. It’s shown in a system alert with limited space.
Step 4: Re-archive and re-upload
Purpose strings are read at archive time. You must:
- Add the key.
- Clean build folder (
⇧⌘K). - Archive again (
Product → Archive). - Upload the new build.
Bumping just the build number without re-archiving won’t fix it — the old archive still lacks the key.
Why this keeps happening on apps that “don’t use” the permission
The single most common cause of a surprise ITMS-90683 is a third-party SDK that links a protected framework. Analytics SDKs that fingerprint via the local network, ad SDKs that link AVCaptureDevice for AR ad formats, crash reporters that read device identifiers. The fix is the same — add the purpose string honestly describing what the SDK does with it — but the deeper hygiene step is auditing what your dependencies actually link. Apple’s list of SDKs that must ship privacy manifests is a good starting list of the usual suspects.
Related
- A vague purpose string is a Guideline 5.1.1(ii) issue — see our full walkthrough of App Store Guideline 5.1.1.
- The privacy manifest is the other declaration Apple cross-references — see resolving ITMS-91053.
- Full submission requirements: every URL and file Apple requires.