ITMS-90683: Fix “Missing purpose string” in Expo
By Mehdi Azizi
Published , 6 min
ITMS-90683 Missing purpose string: why Apple rejects your build, which key to add in app.json with Expo, and how to catch missing keys before you upload.
ITMS-90683 is an automatic rejection from Apple. It shows up by email shortly after you upload your build, before any human review. It means your Info.plist file is missing the sentence that explains why the app accesses sensitive data. The fix takes two steps: add the key named in the message to ios.infoPlist, then run a new build.
I got hit with it on Solys, my mini-game alarm clock, for data the app doesn't even use. Here's what the message means, why it happens, and how to avoid it.
What does the ITMS-90683 error mean?
The full message is titled "ITMS-90683: Missing purpose string in Info.plist". It says your app's code references an API that touches sensitive data (photos, camera, microphone, location, contacts), and your Info.plist doesn't contain the matching description key. The message names that key, for example NSPhotoLibraryUsageDescription.
That description sentence is called a "purpose string". It's the text iOS shows in the permission prompt. Apple says so in its documentation on accessing protected resources: App Review rejects apps whose code accesses these resources without a purpose string.
This isn't a rejection from a reviewer. The check is automatic and runs when the build is delivered, before it goes into review, just like ITMS-91053 for the privacy manifest. The build is discarded and you have to upload a new one.
Why Apple rejects you when your app doesn't use that data
This is the part that catches people off guard. Apple scans the code inside your build, not what your app actually does. If a library you ship contains a reference to the photo library, the key is required, even if no screen ever asks for photo access. Apple's message says it outright: an external library or SDK can reference these APIs, and the purpose string is still mandatory.
Here's my case, on September 26, 2026. While cleaning up the Solys config, I removed the NSPhotoLibraryUsageDescription key, since the app never touches a photo. The next build got rejected with ITMS-90683. The cause: two Expo libraries the app uses, expo-image and expo-file-system, contain code that references the photo library. The previous build went through because the key was still there.
The lesson: you don't remove a description key "because you don't use it". You only remove it once no library in the build references the API anymore.
The most common keys
NSPhotoLibraryUsageDescription: reading or writing photos.NSPhotoLibraryAddUsageDescription: adding photos, without reading.NSCameraUsageDescription: camera.NSMicrophoneUsageDescription: microphone.NSLocationWhenInUseUsageDescription: location while in use.NSContactsUsageDescription: contacts.NSUserTrackingUsageDescription: ad tracking (App Tracking Transparency).
Apple documents each key, for example NSPhotoLibraryUsageDescription: it's required as soon as the app uses an API that reads from or writes to the photo library.
Fixing ITMS-90683 in an Expo app
- Note the key named in Apple's email. The message gives its exact name.
- Add it to your config, under
ios.infoPlist, as shown in Expo's permissions documentation:
{
"expo": {
"ios": {
"infoPlist": {
"NSPhotoLibraryUsageDescription": "Solys doesn't access your photos. This permission is never requested."
}
}
}
}
- Run a new build. Expo is clear about it: an Info.plist change can't ship through an over-the-air update, it needs a new binary.
- Upload the build to Apple, then select it in your version.
One trap if your app is localized: language files translate a key, they don't declare it. The key has to exist in ios.infoPlist first (or in the config of the relevant plugin). Otherwise the app can crash on the first call.
What sentence should you write if your app doesn't use the data?
Apple asks for an accurate, helpful and specific description. If your app really uses the data, say what it's for, in one sentence: "The app uses the camera to scan your ticket's barcode."
If the key is only there because of a library, Apple offers two fixes: write the sentence, or remove the code that accesses the data. When that code comes from a library, you can't just remove it. So on Solys, I wrote the truth: "Solys doesn't access your photos. This permission is never requested." It's a pragmatic choice: the next build passed delivery, but I can't promise Apple will always accept that sentence.
Catching missing keys before you upload
From your project root, this command lists the library files whose iOS code references the most closely watched APIs:
grep -rlE "PHPhotoLibrary|AVCaptureDevice|CLLocationManager|CNContactStore|EKEventStore|ATTrackingManager" \
node_modules/*/ios node_modules/@*/*/ios
Each name maps to a type of data: PHPhotoLibrary for photos, AVCaptureDevice for camera and microphone, CLLocationManager for location, CNContactStore for contacts, EKEventStore for calendar, ATTrackingManager for tracking. For each result, check that the matching description key exists in your config.
This safety net catches the cases I've run into. It doesn't replace reading Apple's email, which is still the only reliable list, same as with the non-public APIs of ITMS-90338. Since that rejection, I run this check before every build: it takes a few seconds, while an ITMS-90683 rejection costs you a build and the time to redo it.
Uploading your build without nasty surprises
ITMS-90683 is quick to fix once you know how to read it, just like ITMS-90725, which targets the Xcode version. The rejections that come after, from a reviewer, need more perspective: the process is on the app rejected by Apple page, and the most common reasons are in why Apple rejects an app.
To check your submission before uploading, the Apple Review Kit bundles my checklist and Claude Code skills that review your project. If your upload is stuck and you want a human to look at it, book an hour with me: we go through your project on a video call, on your screen. And if you're preparing your first release, take the free diagnostic: it puts the steps in order and sends you my Apple anti-rejection checklist.
Frequently asked questions
Is ITMS-90683 an App Review rejection?
Not in the sense of a human reviewer. It's an automatic check run on the build when it's delivered, before it goes into review, like ITMS-90717 for the icon. Nobody opened your app. The build is discarded: you need to fix the Info.plist and upload a new one.
Why does Apple require a key for data my app doesn't use?
Because Apple scans the code in the build, not the app's behavior. If a bundled library references the photo library or the camera, the description key is required, even if no screen ever asks for that access.
Can you fix ITMS-90683 with an over-the-air update?
No. The missing key lives in the Info.plist, which is part of the binary. An over-the-air update doesn't change that file: you have to run a new build and upload it to Apple.
Where do you add NSPhotoLibraryUsageDescription in an Expo project?
In your app config, under ios.infoPlist, with a sentence describing the usage. Some libraries also offer a dedicated setting in their plugin, which can add other keys, like a background mode. Either way, the key has to exist in the base config, not just in the translation files.
Should you remove unused description keys?
Only if no library in the build references the API in question anymore. Otherwise your next upload will be rejected with ITMS-90683. Before removing a key, search for the API name in your dependencies' iOS code.