NS*UsageDescription purpose strings present for all declared permissions
Why it matters
Missing or inadequate NS*UsageDescription strings cause automatic binary rejection — apps without them cannot be installed on TestFlight, let alone the App Store. Apple enforces this at the binary validation stage before human review begins. Beyond rejection, an empty or generic string like 'We need camera access' violates GDPR Art.5(1)(b) (purpose limitation) by failing to communicate the specific feature requiring access, and CCPA §1798.100 by withholding disclosure of why personal data is collected. Every permission your code requests must be matched with a substantive, feature-specific explanation.
Severity rationale
Critical because missing NS*UsageDescription keys cause automatic binary rejection — the app cannot be distributed on TestFlight or the App Store under any circumstance.
Remediation
For Expo managed workflow, add all permission descriptions to app.json under expo.ios.infoPlist. Each description must name the specific feature — not just the data type:
{
"expo": {
"ios": {
"infoPlist": {
"NSCameraUsageDescription": "The camera lets you attach photos to your expense reports and scan receipts.",
"NSLocationWhenInUseUsageDescription": "Your location is used to find nearby merchants and pre-fill expense addresses."
}
}
}
}
For native iOS, edit Info.plist directly in Xcode. Write descriptions in first person from the app's perspective. Audit every permission API call in the codebase and verify a matching key exists before every submission.
Detection
- ID:
ns-usage-descriptions-complete - Severity:
critical - What to look for: First enumerate all permission-triggering code in the project. For React Native/Expo: search for
requestPermissionsAsync,requestCameraPermissionsAsync,requestMicrophonePermissionsAsync,requestForegroundPermissionsAsync,requestBackgroundPermissionsAsync,requestContactsPermissionsAsync,requestCalendarPermissionsAsync,PermissionsAndroid.request,AVCaptureDevice.requestAccess,UNUserNotificationCenter.requestAuthorization,ATTrackingManager.requestTrackingAuthorization. For Flutter:permission_handlerplugin calls (Permission.camera.request(),Permission.location.request(), etc.). For native Swift:CLLocationManager.requestWhenInUseAuthorization(),PHPhotoLibrary.requestAuthorization(),AVCaptureDevice.requestAccess(for:),CNContactStore().requestAccess(for:). Then verify each has the correspondingNS*UsageDescriptionkey inInfo.plist(orapp.jsonios.infoPlist). The string value must be substantive: it must explain WHY the permission is needed in terms the user understands (not "We need camera access" — instead "We need camera access to let you scan receipts and attach photos to expenses"). Check for: empty strings; generic strings that don't mention the specific feature; placeholder strings like "Permission required" or "Used for app functionality". - Pass criteria: Every permission used in code has a corresponding
NS*UsageDescriptionkey with a genuine, feature-specific explanation in Info. At least 1 implementation must be verified.plist / app.json. - Fail criteria: Any permission API called in code without the corresponding
NS*UsageDescriptionkey; or a key is present but its value is empty, generic, or a placeholder. - Skip (N/A) when: App targets Android only and has no iOS build target.
- Detail on fail:
"Camera permission requested in src/screens/ProfileScreen.tsx but NSCameraUsageDescription is missing from Info.plist"or"NSLocationWhenInUseUsageDescription is set to 'We need your location' — too generic; Apple requires a specific feature explanation" - Remediation: Missing or inadequate
NS*UsageDescriptionkeys cause automatic binary rejection — apps with missing strings cannot be installed even on TestFlight.- For Expo managed workflow, add all descriptions to
app.jsonunderexpo.ios.infoPlist:{ "expo": { "ios": { "infoPlist": { "NSCameraUsageDescription": "The camera lets you attach photos to your expense reports and scan receipts.", "NSLocationWhenInUseUsageDescription": "Your location is used to find nearby merchants and pre-fill expense addresses." } } } } - For native iOS, edit
Info.plistdirectly in Xcode or a text editor - Write descriptions in the first person from the app's perspective, mentioning the specific feature that uses the permission
- For Expo managed workflow, add all descriptions to
External references
- external · apple-requesting-permission — Requesting permission to use system features (NS*UsageDescription)
- gdpr · Art.5(1)(b) — Purpose limitation
- gdpr · Art.5(1)(c) — Data minimisation
- ccpa · §1798.100 — Right to know about personal information collected
Taxons
History
- 2026-04-18·v1.0.0·Initial import from app-store-privacy-data·automated