Expo

Get Started
API Reference

Permissions

When you are creating an app that requires access to potentially sensitive information on a user's device, such as their location or contacts, you need to ask for the user's permission first. The expo-permissions module makes requesting these permissions easy, fast, and reliable.
Please read the permissions on iOS and permissions on Android sections carefully before deploying your app to the stores. If you don't configure or explain the permissions properly it may result in your app getting rejected or pulled from the stores. Read more about deploying to the stores in the App Store Deployment Guide.

Platform Compatibility

Android DeviceAndroid EmulatoriOS DeviceiOS SimulatorWeb

Installation

expo install expo-permissions

If you're installing this in a bare React Native app, you should also follow these additional installation instructions.

To request permissions on iOS, you have to describe why the permissions are requested and install the library that can request this permission. In the managed workflow, you can do that by customizing the ios.infoPlist property in your app.json file. When using the bare workflow, you have to edit the info.plist file directly.
See the Permission types below to learn about what infoPlist property you need for each permission. You can find the full list of available properties in Apple's InfoPlistKeyReference. Apple also documents the basic guidelines for the structure of the message in the Human Interface Guidelines.
Note: apps using permissions without descriptions may be rejected from the App Store. (see the App Store Deployment Guide)

On Android, permissions are little bit simpler than iOS. In the managed workflow, permissions are controlled via the android.permissions property in your app.json file. In the bare workflow, they have to be defined in your AndroidManifest.xml.
Some Expo and React Native modules include permissions by default. If you use expo-location, for example, both the ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION are implied and added to your app's permissions automatically.
To limit the permissions your managed workflow app requires, set the android.permissions property in your app.json file to list only the permissions you need, and Expo will also include the minimum permissions it requires to run. If you leave this property out, all permissions will be included in your app. When using the bare workflow, you have to blacklist permissions in your AndroidManifest.xml manually.
See the Permission types below to learn about which Android permissions are added. You can find a full list of all available permissions in the Android Manifest.permissions reference.
Note: see the android.permissions documentation to learn about which permissions are always included.
Note: apps using dangerous or signature permissions without valid reasons may be rejected by Google. Make sure you follow the Android permissions best practices when submitting your app.
Note: by default, the permissions implied by the modules you installed are added to the AndroidManifest.xml. To exclude permissions, you have to define the android.permissions manifest property or blacklist them in the bare workflow.

On web permissions like the Camera and Location can only be requested from a secure context, e.g. using https:// or http://localhost. This limitation is similar to Android's manifest permissions and iOS's infoPlist usage messages and enforced to increase privacy.

Often you want to be able to test what happens when a user rejects a permission, to ensure that it has the desired behavior. An operating-system level restriction on both iOS and Android prohibits an app from asking for the same permission more than once (you can imagine how this could be annoying for the user to be repeatedly prompted for permissions). So in order to test different flows involving permissions in development, you may need to uninstall and reinstall the Expo client app. In the simulator this is as easy as deleting the app, and expo-cli will automatically install it again next time you launch the project.

expo-permissions includes the shared infrastructure for handling system permissions. On iOS, it does not include the code specific to particular permissions. For example, if you want to use the CAMERA_ROLL permission, you need to install expo-image-picker or expo-media-library.
The following table shows you which permissions correspond to which packages.
Permission typePackages
NOTIFICATIONSexpo-notifications
USER_FACING_NOTIFICATIONSexpo-notifications
LOCATIONexpo-location
CAMERAexpo-barcode-scanner
expo-camera
expo-face-detector
expo-image-picker
expo-media-library
AUDIO_RECORDINGexpo-av
CONTACTSexpo-contacts
CAMERA_ROLLexpo-image-picker
expo-media-library
CALENDARexpo-calendar
REMINDERSexpo-calendar
SYSTEM_BRIGHTNESSexpo-brightness
MOTIONexpo-sensors

When adding Expo and other React Native modules to your project, certain Android permissions might be implied automatically. The modules should only add relevant permissions required to use the module, however, sometimes you may want to remove some of these permissions.
Since the android.permissions manifest property doesn't work in the bare workflow- when you want to exclude specific permissions from the build, you have to "blacklist" them in your AndroidManifest.xml. You can do that with the tools:node="remove" attribute on the <use-permission> tag.
<manifest xmlns:tools="http://schemas.android.com/tools">
  <uses-permission tools:node="remove" android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
Note: you have to define the xmlns:tools attribute on <manifest> before you can use the tools:node attribute on permissions.

API

import * as Permissions from 'expo-permissions';

const [permission, askPermission, getPermission] = usePermissions(Permissions.CAMERA, { ... });
Get or ask permission for protected functionality within the app. This returns the result for the requested permissions. It also returns additional callback to interact based on user input.

  • permissionTypes (Type|Type[]) -- One or more types to get or ask permission for. After the permission status is fetched, you can show different UI based on the current status.
  • permissionOptions -- Optional configuration to change the behavior of the hook.
    • get (boolean) -- Retrieves the permission status without interacting with the user, true by default.
    • ask (boolean) -- Prompts the user with the requested permission directly. Without using the askPermission callback, false by default.

  • permission (PermissionsResponse|undefined) -- An object with information about the permissions, including status, expiration, and scope (if applicable).
  • askPermission (() => void) -- A callback to ask the user for permission.
  • getPermission (() => void) -- A callback to get the permission status without interacting with the user.

function App() {
  const [permission, askForPermission] = usePermissions(Permissions.CAMERA, { ask: true });

  if (!permission || permission.status !== 'granted') {
    return (
      <View>
        <Text>Permission is not granted</Text>
        <Button title="Grant permission" onPress={askForPermission} />
      </View>
    );
  }

  return (
    <View>
      <Camera />
    </View>
  );
}

Determines whether your app has already been granted access to the provided permissions types.

  • permissionTypes (string) -- The names of the permissions types.

A Promise resolving to a PermissionResponse object -- an object describing the current state of the permissions.

async function alertIfRemoteNotificationsDisabledAsync() {
  const { status } = await Permissions.getAsync(Permissions.NOTIFICATIONS);
  if (status !== 'granted') {
    alert('Hey! You might want to enable notifications for my app, they are good.');
  }
}

async function checkMultiPermissions() {
  const { status, expires, permissions } = await Permissions.getAsync(
    Permissions.CALENDAR,
    Permissions.CONTACTS
  );
  if (status !== 'granted') {
    alert('Hey! You have not enabled selected permissions');
  }
}

Prompt the user for types of permissions. If they have already granted access, response will be success.

  • types (string) -- The names of the permissions types.

A Promise resolving to a PermissionResponse -- an object describing the new state of the permissions, after asking the user.

async function getLocationAsync() {
  // permissions returns only for location permissions on iOS and under certain conditions, see Permissions.LOCATION
  const { status, permissions } = await Permissions.askAsync(Permissions.LOCATION);
  if (status === 'granted') {
    return Location.getCurrentPositionAsync({ enableHighAccuracy: true });
  } else {
    throw new Error('Location permission not granted');
  }
}

The permission response is an object describing the current state of the requested permission(s). This response contains the top-level status, granted, expires and canAskAgain properties representing the outcome for all individual permissions.
interface PermissionResponse {
  status: 'granted' | 'undetermined' | 'denied';
  granted: boolean;
  expires: 'never' | number;
  canAskAgain: boolean;
  permissions: { // an object with an entry for each permission requested
    [permissionType: string /* PermissionType */]: PermissionInfo;
  };
}

This property is either granted, undetermined or denied, based on the requested permissions. It's reducted using the following rules.
  • When one or more permissions are undetermined, the status is undetermined
  • When one or more permissions are denied, but none of them are undetermined, the status is denied
  • When all permissions are granted, the status is granted.
Here are some examples of permission statuses and the top-level status.
[granted, granted, granted] => granted
[granted, granted, denied] => denied
[denied, denied, denied] => denied
[granted, granted, undetermined] => undetermined
[granted, denied, undetermined] => undetermined

This property is set to true when all requested permission are granted. If one or more are denied or undetermined, this is set to false.

This property coincides with the expiration time of the permission that expires the earliest. When none of the requested permissions expires, it's set to never.

This property is set to true when the app can request the user to grant all requested permissions.

This object contains information, per requested permission, using the PermissionInfo type.

This object contains information about a single requested permission, it's retuned within the PermissionResponse using the permissions property. It also may include additional platform-specific info, like the scope of the permission.
interface PermissionInfo {
  status: 'granted' | 'undetermined' | 'denied';
  granted: boolean;
  expires: 'never' | number;
  canAskAgain: boolean;
  ios?: {
    scope: 'whenInUse' | 'always';
  };
  android?: {
    scope: 'fine' | 'coarse' | 'none';
  };
}

The permission type for user-facing notifications and remote push notifications.
  • Android: it doesn't require any permissions in your manifest.
  • iOS: it requires the expo-notifications module and doesn't require a message.
Note (iOS): Asking for this permission asks the user not only for permission to register for push/remote notifications, but also for showing notifications as such. At the moment remote notifications will only be received when notifications are permitted to play a sound, change the app badge or be displayed as an alert. As iOS is more detailed when it comes to notifications permissions, this permission status will contain not only status and expires, but also Boolean values for allowsSound, allowsAlert and allowsBadge.
Note (iOS): This does not disambiguate undetermined from denied and so will only ever return granted or undetermined. This is due to the way the underlying native API is implemented. On iOS simulators, since they don't support registering for push notifications, you will always get undetermined result.
Note (Android): Android does not differentiate between permissions for local and remote notifications, so status of permission for NOTIFICATIONS should always be the same as the status for USER_FACING_NOTIFICATIONS.

The permission type for user-facing notifications. This does not register your app to receive remote push notifications; see the NOTIFICATIONS permission.
  • Android: this permission is the same as NOTIFICATIONS and returns the status from that permission. _ iOS: it requires the expo-notifications module and doesn't require a message.
Note (iOS): It provides more detailed permissions, so the permission status will contain not only status and expires, but also Boolean values for allowsSound, allowsAlert and allowsBadge.

The permission type for location access. It contains additional field when returning:
Note (iOS): This is not working with this permission being not individually, Permissions.askAsync(Permissions.SOME_PERMISSIONS, Permissions.LOCATION, Permissions.CAMERA, ...) would throw. On iOS ask for this permission type individually.
Note (iOS): In Expo client on iOS this permission will always ask the user for permission to access location data while the app is in use.
If you would like to access location data in a standalone app, note that you'll need to provide location usage descriptions in app.json. For more information see Deploying to App Stores guide.

Returns whether permission is granted only for location updates when app is in use (whenInUse), even when app is backgrounded (always) or when permission is not granted (none). On devices running Android in versions lower than 10, scope value is either always or none depending on permission being granted. There is no special background location permission on Android 9 and below.

Due to the design of the location permission API on iOS we aren't able to provide you with methods for asking for whenInUse or always location usage permission specifically. However, you can customize the behavior by providing the following sets of usage descriptions:
  • if you provide only NSLocationWhenInUseUsageDescription, your application will only ever ask for location access permission "when in use",
  • if you provide both NSLocationWhenInUseUsageDescription and NSLocationAlwaysAndWhenInUseUsageDescription, your application will only ask for "when in use" permission on iOS 10, whereas on iOS 11+ it will show a dialog to the user where he'll be able to pick whether he'd like to give your app permission to access location always or only when the app is in use,
  • if you provide all three: NSLocationWhenInUseUsageDescription, NSLocationAlwaysAndWhenInUseUsageDescription and NSLocationAlwaysUsageDescription, your application on iOS 11+ will still show a dialog described above and on iOS 10 it will only ask for "always" location permission.

The permission type for photo and video taking.
Note (iOS): You can request this permission with the expo-barcode-scanner, expo-camera, expo-face-detector, expo-image-picker, or expo-media-library module.

The permission type for audio recording.

The permission type for reading or writing contacts.

The permission type for reading or writing to the camera roll.
Note (iOS): iOS provides more detailed permissions, returning { status, permissions: { cameraRoll: { accessPrivileges } } } where accessPrivileges can be:
  • all if the user granted your app access to the whole photo library
  • limited if the user granted your app access only to selected photos (only available on iOS 14.0+)
  • none if user denied or hasn't yet granted the permission

The permission type for reading or writing to the calendar.

The permission type for reading or writing reminders.
  • Android: this permission has no effect on Android and is resolved as granted immediately.
  • iOS: it requires the expo-calendar module and NSRemindersUsageDescription message.

A permission to change the brightness of the screen, system wide.
  • Android: it requires the WRITE_SETTINGS permission in your manifest.
  • iOS: this permission has no effect on iOS and is resolved as granted immediately.

The permission for accessing DeviceMotion and DeviceOrientation in the web browser. This can only be requested from a website using HTTPS (expo web --https). This permission cannot be silently retrieved, you can only request it. This permission can only be requested with a user interaction i.e. a button press.