docs

Permissions

+
UniversalWorks with Expo & React Native CLI

This tool works with both Expo and React Native CLI projects. Just install and go.

Every permission screen in your app has several paths: the first ask, the refusal, the "turn it on in Settings" message, approximate location, and a user who said no months ago. To see them on a real device you'd have to dig through Settings or reinstall the app. Permissions lets you pick the state your app sees, and only your app sees it. The device's real settings stay the same.

Install

npm install @buoy-gg/permissions

Permissions shows up in your FloatingDevTools menu on its own. If your app checks a permission while it starts up, import it first in your entry file:

js
// index.js
import "@buoy-gg/permissions";
import "expo-router/entry";
// index.js
import "@buoy-gg/permissions";
import "expo-router/entry";

It works with these libraries, with no setup:

  • Expo modules: expo-location, expo-camera, expo-notifications, expo-image-picker, expo-media-library, expo-contacts, expo-calendar, expo-tracking-transparency, expo-audio, expo-sensors and expo-maps, including their use…Permissions hooks
  • React Native's PermissionsAndroid
  • react-native-permissions

How to use it

Open Permissions and you'll see the permissions your app has checked. Tap one and pick what the app sees:

OptionWhat your app sees
Phone's SettingWhat the device really says. This is the default.
Not AskedThe app has never asked. The next request shows a prompt.
AllowedFull access.
Approximate, Selected Photos, Selected Contacts, ProvisionalLimited access. Only the permissions and platforms that have it offer it.
DeniedThe user said no. On Android the app can ask once more. On iOS it can't, so the app has to send the user to Settings.
BlockedAndroid only: the user said no twice, so only Settings can change it.
RestrictediOS only: Screen Time or device management turned it off.

A simulated row shows its value in green, with the phone's real setting under it. Permissions your app can ask for but hasn't yet are under Other Permissions. Use Real Permissions puts every row back.

A small strip stays on screen while anything is simulated, so you don't forget. Tap it to open Permissions. Its X puts every permission back, and Undo brings them back for a few seconds after. Changes stay after a reload.

What happens when the app asks

While a permission is simulated, the real system prompt never shows, because tapping it would change the device's real setting. When your app asks from Not Asked, Buoy shows its own prompt with the same buttons, including Allow Once. On iOS it shows your purpose string when your Expo config sets it (ios.infoPlist or a config plugin option like expo-camera's cameraPermission). Pick an answer and the permission moves to that state, the way the phone would. Allow Once goes back to Not Asked when the app restarts.

When your app opens its Settings page (Linking.openSettings() or an app-settings: link), Buoy shows a small Settings stand-in with the options the Settings app uses, like Never, Ask Next Time and While Using the App. When you pick one, your app gets the same "back from the background" event it would get from the real Settings app.

Changing a row sends that event too, so screens that check again when the app comes back update right away. If a screen read the permission before the change and hasn't read it since, the row says so and offers Reload App.

What stays real

Native code that checks the device itself still sees the real setting. While a permission is refused, calls like getCurrentPositionAsync, launchCameraAsync and media library reads fail with the same error the real module throws, and Approximate location rounds positions to about 2 km. The camera preview itself can't be faked, so CameraView still follows the device.

When you pick Allowed but the phone hasn't allowed the permission yet, the permission's page offers Show Real Prompt. It shows the real prompt once so the device can grant it. On a simulator, the MCP server can also grant, revoke or reset the real setting for you.

FAQ

Does this change my phone's settings?

No. Only your app sees the new state. Use Show Real Prompt, or the MCP server's system_permission on a simulator, to change the real setting.

Why does my screen still show the old state?

It hasn't checked again yet. Most screens check when they open or when the app comes back to the front. Go back and open the screen again, or tap Reload App under the row.

Can AI agents use it?

Yes. The MCP server has get_permissions, permission_action and system_permission, and Ask Buoy can do it when you ask, like "show me the store finder when location is denied". Buoy Desktop has a Permissions panel too.