iOS Info.plist keys
Info.plist is the property list that describes an iOS app to the system:
its bundle identity, version, UI configuration, and — critically — the privacy
usage-description strings the system shows when requesting access to protected
resources. Missing or vague usage strings cause runtime crashes and App Review
rejections. This searchable reference covers the keys that matter most.
Why Info.plist matters beyond just configuration
Two categories of keys cause the most real-world problems:
Version keys (CFBundleShortVersionString and CFBundleVersion): these are separate concepts. The marketing version (2.1.0) can stay the same across multiple TestFlight uploads; the build number must increment every single time. Forgetting to bump the build number causes a silent upload failure in App Store Connect.
Privacy usage descriptions: every protected resource — camera, microphone, location, contacts, photos, health data, Bluetooth, tracking — requires its own NSxUsageDescription string in Info.plist. iOS reads this string at runtime and shows it in the system permission prompt before your code even runs. If the key is missing, the app crashes the instant it attempts to access that resource. App Review independently checks that usage strings are present, non-empty, and meaningful; submitting “This app uses the camera” for NSCameraUsageDescription when you actually scan medical documents is a common rejection reason.
How it works
Keys are entries in a plist, each with a type (String, Boolean, Array, Dict):
<key>CFBundleShortVersionString</key>
<string>2.1.0</string>
<key>CFBundleVersion</key>
<string>57</string>
<key>NSCameraUsageDescription</key>
<string>Scans receipts to attach to your warranty claim.</string>
Bundle keys establish identity and versioning; CFBundleVersion must increase
every upload. Each NSxUsageDescription key pairs with a protected API — access
the camera without NSCameraUsageDescription and iOS terminates the app on the
spot.
Common permission keys and their required descriptions
| Key | Protected resource | Required when |
|---|---|---|
NSCameraUsageDescription | Camera | Capturing photos or video |
NSMicrophoneUsageDescription | Microphone | Recording audio |
NSLocationWhenInUseUsageDescription | Location (foreground) | Showing user location on a map |
NSLocationAlwaysAndWhenInUseUsageDescription | Location (background) | Background tracking |
NSPhotoLibraryUsageDescription | Photo library (read) | Picking images from Photos |
NSPhotoLibraryAddUsageDescription | Photo library (save) | Saving images to Photos |
NSContactsUsageDescription | Contacts | Reading address book |
NSBluetoothAlwaysUsageDescription | Bluetooth | Connecting to BLE peripherals |
Writing a usage string that passes review
Bad: "This app uses the camera."
Good: "We use your camera to scan documents and attach them to your support ticket."
Apple wants the string to tell the user concretely what the app does with the data, not just that it accesses the resource. Generic or boilerplate strings are a reliable rejection trigger.
Tips and notes
- Write specific usage strings — say what the data is used for, not just that it is accessed.
- Bump
CFBundleVersionon every App Store Connect upload, even for the same marketing release. LSApplicationQueriesSchemesis needed before callingcanOpenURLfor third-party URL schemes.- In Expo and React Native, set Info.plist keys via
app.jsonunderios.infoPlistor through config plugins rather than editing the generated file directly — the file is overwritten on each Prebuild. - In modern Xcode, many keys are managed under the target’s Info tab or in build settings; you still add custom and usage-description keys there directly.