Users who see an unexpected system permission dialog — with no context about why an app needs access — deny at significantly higher rates than users who receive an explanation first. iOS only allows one native permission request per permission type: if the user denies the cold prompt, the app can never ask again via the system dialog. GDPR Art. 7 requires consent to be freely given, informed, and specific; a system dialog with no preceding rationale does not satisfy the informed requirement. Google Play's permission UX guidelines similarly require that the app explain the purpose before the native prompt fires. A denied permission that could have been granted represents a permanently lost capability — the user must manually navigate to Settings to re-enable it.
High because a denied permission from a cold, unexplained prompt is permanent on iOS and permanently degrades the feature — the only recovery requires the user to find and change a system-level setting.
Display an in-app explanation modal before every sensitive permission request. Keep the rationale specific to the feature the user is about to use.
import { Alert } from 'react-native'
import { request, PERMISSIONS, RESULTS } from 'react-native-permissions'
async function requestMicrophoneWithRationale() {
await new Promise<void>(resolve =>
Alert.alert(
'Microphone Access',
'Voice messages require microphone access. We never record without your action.',
[{ text: 'Continue', onPress: resolve }]
)
)
const result = await request(PERMISSIONS.IOS.MICROPHONE)
return result === RESULTS.GRANTED
}
The rationale must reference the specific feature ("voice messages"), not vague purpose ("improve your experience"). For Android, set rationale directly in the request() call options — the library surfaces it via Android's built-in rationale dialog.
ID: mobile-permissions-privacy.permission-requests.permission-rationale
Severity: high
What to look for: Count all sensitive permission request calls (camera, location, contacts, calendar, photos, microphone). For each, check whether explanatory text, an alert, or a rationale screen is shown before the native permission prompt. Quote the actual rationale text found (or note its absence).
Pass criteria: At least 100% of sensitive permission requests have a rationale shown before the native prompt. The rationale explains why the permission is needed in context of the feature. Report the ratio: "X of Y sensitive permission requests include rationale."
Fail criteria: Any sensitive permission request prompt appears with no prior explanation, leaving users confused about why the app needs access.
Skip (N/A) when: App requests no sensitive permissions (no camera, location, contacts, calendar, photos, or microphone).
Detail on fail: Name the permissions that lack rationale. Quote the request call. Example: "Camera permission is requested with no explanation shown to user" or "Contact list permission request appears with no prior rationale screen"
Remediation: Users are more likely to grant permissions when they understand why they're needed. Show a brief explanation before each permission prompt:
import { request, PERMISSIONS, RESULTS } from 'react-native-permissions'
async function requestCameraWithRationale() {
// Show explanation first
Alert.alert(
'Camera Access',
'We need camera access to enable video calls',
[
{ text: 'Cancel', onPress: () => {} },
{
text: 'Grant',
onPress: async () => {
const result = await request(PERMISSIONS.IOS.CAMERA)
if (result === RESULTS.GRANTED) {
// camera granted
}
},
},
]
)
}