ITMS-90683 means the uploaded app can access a protected resource but its final Info.plist does not contain the required purpose string. The fix is not to add every privacy key. Find the resource App Store Connect named, identify which code can reach it, and declare an honest user-facing reason only if the app actually needs that access.
Read the key in the message
The upload message normally names a missing key such as NSCameraUsageDescription, NSMicrophoneUsageDescription, or NSPhotoLibraryUsageDescription. That key is your starting point. Apple's protected resource reference explains which purpose string belongs to each resource.
"This app needs camera access" repeats the permission name. A useful string explains the action: "Take a profile photo" or "Scan a receipt to attach it to an expense."
Find who references the resource
- Search the app target for the API or capability named in the warning.
- Check extensions and embedded frameworks, not only the main target.
- Review recently added SDKs and optional modules. A dependency can reference a protected API even when your UI never calls it.
- Decide whether the release build needs the feature. Remove the unused code path or add the correct declaration.
Check the final app bundle
Export the same Release archive you upload, then inspect the processed plist inside the .app bundle. Apple's Info.plist guide describes how Xcode merges target settings and supplied plist files.
unzip YourApp.ipa -d ipa-check
plutil -p ipa-check/Payload/YourApp.app/Info.plist \
| grep UsageDescriptionWrite a purpose string that survives review
- Name the user action that triggers access.
- Explain what the data enables inside the app.
- Match the current product, not a planned feature.
- Localize the string for every supported language.
- Test the system prompt on a clean install.
Upload a new binary
Changing store metadata does not modify the app bundle. Increment the build number, archive the exact release configuration, verify the processed plist, and upload a new binary. Keep the original message in the release ticket so the same dependency cannot silently reintroduce the issue later.
Was this article helpful?