Meta description: My app got rejected by Apple for missing NSUsageDescription keys. Here’s the exact fix, the keys you need, and how to avoid rejection on your next submission.
Last updated: May 2026
The Rejection Email Nobody Wants to See
I was three days from a client’s launch deadline when Apple rejected the app. The reason: “Missing purpose string in Info.plist.” I had tested the app thoroughly. It worked flawlessly in TestFlight. But we hadn’t added the required privacy description strings for camera and photo library access, and Apple doesn’t let that slide.
App Store rejection for missing privacy descriptions is one of the most common — and most preventable — rejection reasons developers face. Apple’s privacy review process has become increasingly strict since iOS 14, and if you’re not explicitly declaring why your app accesses sensitive hardware or data, your submission will get flagged every time.
This guide covers exactly how to diagnose and fix this issue, the keys you’re most likely missing, and how to build a submission checklist so this never delays a launch again.
TL;DR
- Apple requires an
NSUsageDescriptionstring inInfo.plistfor every sensitive API your app accesses - You must explain why your app needs access in plain English — vague strings like “Required for app functionality” will get rejected
- Adding the required keys in Xcode’s Info.plist editor or directly in the XML source resolves the issue immediately
Why Apple Requires Privacy Usage Descriptions
Apple introduced mandatory NSUsageDescription keys as part of its broader privacy framework. The goal is transparency: when iOS shows a permission prompt to the user, the description you write is what they read. It’s your one chance to explain, in plain language, why you need access to their camera, location, microphone, or contacts.
From a technical standpoint, if you call any API that touches a protected resource — camera, photo library, location services, health data, Bluetooth, and more — and the corresponding usage description key is missing from your Info.plist, your app will crash at runtime on device (with a SIGABRT) and get rejected by App Store Review.
Important: Apple’s App Review Guidelines state that apps “must include a usage description for any privacy-sensitive APIs accessed in the app’s binary, even if the code path that accesses the data is never triggered by the user.” Third-party SDKs are included — if a library you import touches the camera, you need the key, even if your own code doesn’t call it directly. [SOURCE: https://developer.apple.com/documentation/uikit/protecting_the_user_s_privacy]
Prerequisites
To follow along, you’ll need:
- Xcode 15 or later
- An active Apple Developer account
- Your project’s
Info.plistaccessible (or the equivalentInfosection under your Target settings in Xcode 15+) - Basic familiarity with iOS project structure
How to Diagnose the Exact Keys You’re Missing
Step 1 — Read the Rejection Notice Carefully
When Apple rejects your app, the resolution center message will usually name the specific API or framework triggering the issue. Look for phrases like:
Your app uses the Camera (NSCameraUsageDescription),
but Info.plist does not have a NSCameraUsageDescription key.
Screenshot that message. Each missing key will be listed explicitly.
Step 2 — Run a Static Analysis on Your Binary
Even before submitting, you can find missing keys yourself. After building your app archive, run:
bash
grep -r "NSUsageDescription" /path/to/YourApp.app/
This shows every description string bundled in your binary. Cross-reference this with the APIs your app (and your third-party SDKs) actually call.
A more powerful approach — especially for finding keys required by third-party SDKs — is to check the SDK documentation directly. Firebase, for example, will require NSCameraUsageDescription if you use ML Kit’s text recognition. Stripe’s SDK may trigger NSCameraUsageDescription for card scanning. Always audit your Podfile or Package.swift dependencies.
Step 3 — Check Xcode’s Privacy Report
In Xcode 15+, go to Product → Archive, then in the Organizer window, select your archive and click Generate Privacy Report. This produces a JSON file listing every API category your app accesses, which is the same signal Apple’s automated review tooling uses.
bash
# You can also inspect the report from CLI after archiving
cat ~/Library/Developer/Xcode/Archives/.../PrivacyReport.json
Adding the Missing Keys: Step by Step
Step 4 — Open Info.plist in Xcode
In Xcode 15+, Info.plist editing moved. Navigate to:
Your Target → Info tab → Custom iOS Target Properties
Or open the Info.plist file directly in the file navigator. Right-click and choose Open As → Source Code to edit the XML directly — I find this faster for adding multiple keys at once.
Step 5 — Add the Required NSUsageDescription Keys
Here are the most commonly required keys and what Apple expects in the value:
xml
<!-- Camera access -->
<key>NSCameraUsageDescription</key>
<string>We use your camera to let you scan documents and upload photos to your account.</string>
<!-- Photo library read access -->
<key>NSPhotoLibraryUsageDescription</key>
<string>We access your photo library so you can select and upload images to your profile.</string>
<!-- Photo library write access (saving images) -->
<key>NSPhotoLibraryAddUsageDescription</key>
<string>We save processed images directly to your photo library for easy access.</string>
<!-- Microphone -->
<key>NSMicrophoneUsageDescription</key>
<string>We use your microphone to record audio messages and voice notes.</string>
<!-- Location while in use -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>We use your location to show nearby results and improve search relevance.</string>
<!-- Location always (requires strong justification) -->
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>We use background location to notify you of relevant events near your saved places.</string>
<!-- Contacts -->
<key>NSContactsUsageDescription</key>
<string>We access your contacts so you can quickly invite friends to connect on the app.</string>
<!-- Bluetooth -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>We use Bluetooth to connect with nearby devices for content sharing.</string>
<!-- Face ID -->
<key>NSFaceIDUsageDescription</key>
<string>We use Face ID to authenticate your identity for secure account access.</string>
Pro Tip: Apple reviewers read these strings. Generic descriptions like “This permission is required” or “Used by the app” have historically triggered manual review flags and secondary rejections. Write one clear sentence explaining the user benefit. [SOURCE: https://developer.apple.com/documentation/bundleresources/information_property_list/protected_resources]
Step 6 — Verify the Keys Are Present in Your Archive
Before resubmitting, build and archive the app, then inspect the binary:
bash
# Extract and check Info.plist from the .ipa
unzip -o YourApp.ipa -d YourAppExtracted
plutil -p YourAppExtracted/Payload/YourApp.app/Info.plist | grep UsageDescription
Every key you added should appear in the output. If a key is missing here, it won’t be in the submission.
Real-World Tips I Use in Production
Audit third-party SDKs before starting integration, not after. When I add a new pod or Swift package, I immediately check its documentation for required Info.plist keys. Firebase, Stripe, Mapbox, and most major SDKs have a dedicated “privacy” or “permissions” section. Catching this early is far cheaper than a rejection cycle.
Add a privacy keys template to your project scaffolding. I maintain a base Info.plist snippet in our internal project template that includes the 10 most common usage description keys with placeholder values. Developers fill in the appropriate descriptions during feature development, not at submission time.
Use Apple’s Privacy Nutrition Labels as a checklist. When filling out your App Store Connect privacy questionnaire, every data type you declare there should have a corresponding NSUsageDescription key in your Info.plist. If they don’t match, you’ll likely face rejection.
Common Errors and How I Fixed Them
Error: App crashes on device with SIGABRT when accessing camera — but the key is in Info.plist Cause: The key was added to the wrong target. In multi-target projects (main app + extensions), each target needs its own set of keys. Fix: Check the Target Membership of your Info.plist and duplicate the key in each relevant target’s plist.
Error: App rejected for NSBluetoothAlwaysUsageDescription but the app doesn’t use Bluetooth Cause: A third-party SDK (analytics or crash reporting library) imports CoreBluetooth internally, even if the feature isn’t used. Fix: Add the key with an honest description, or contact the SDK vendor about stripping Bluetooth from their framework. Some SDKs offer slim build variants.
Error: Resubmission rejected again for the same key after adding it Cause: The description value was too vague (“Used for app features”) and triggered a secondary human review flag. Fix: Rewrite the description to be specific about the user-facing feature that requires the permission. Reference the exact screen or action.
FAQ
Q: What happens if I don’t add NSUsageDescription keys and my app accesses a protected API? A: On device, the app will crash immediately with a SIGABRT exception when the system tries to prompt for permission. In App Store review, the submission will be rejected automatically before it ever reaches a human reviewer.
Q: Do I need NSUsageDescription keys for APIs I import but never call at runtime? A: Yes. Apple’s static analysis scans your binary for framework imports and API references, not actual runtime call paths. If a third-party SDK you include links against a protected framework, you need the corresponding key.
Q: How specific do my privacy description strings need to be to pass App Review? A: Specific enough that a non-technical user understands the direct benefit. “We use your camera to scan receipts and automatically fill expense reports” passes. “Camera access is required” does not. The more user-benefit-oriented the language, the better.
Q: Can I add usage description keys to a React Native or Flutter app the same way? A: Yes. In React Native, edit the Info.plist file directly inside the ios/ folder. In Flutter, it’s located at ios/Runner/Info.plist. The XML format and key names are identical regardless of framework.
Q: What’s the difference between NSPhotoLibraryUsageDescription and NSPhotoLibraryAddUsageDescription? A: NSPhotoLibraryUsageDescription covers read access — selecting photos from the library. NSPhotoLibraryAddUsageDescription covers write access — saving new photos to the library. If your app does both, you need both keys. Missing either one will cause rejection if the corresponding action is triggered.
Conclusion
App Store rejection for missing privacy descriptions is entirely preventable once you understand Apple’s static analysis model. The fix is straightforward — add the correct NSUsageDescription keys with clear, user-focused descriptions — but the real win is building a habit of auditing these keys early in development, not at submission time.
Treat your Info.plist privacy keys as a first-class part of your feature checklist. Every API that touches protected resources needs a key, every key needs an honest description, and every description needs to explain the user benefit clearly.
About the Author: I’m an iOS developer with 9 years of experience shipping apps across healthcare, fintech, and consumer categories on the App Store. I work primarily in Swift and SwiftUI, and I’ve navigated more App Review rejections — and appeals — than I care to count. I write these guides so other developers can skip the pain I went through.

