App Store

    How do you fix ITMS-91053 Missing API Declaration?

    Xcode editor showing a PrivacyInfo.xcprivacy file with NSPrivacyAccessedAPITypes entries for UserDefaults and FileTimestamp categories with approved reason codes

    If you opened App Store Connect this morning and saw a red banner with ITMS-91053 next to your build number, the build did not fail for a code signing reason or a metadata reason. It failed because Apple's automated check found a call to one of the Required Reason APIs without a matching declaration in your privacy manifest. The fix is mechanical once you know which API and which reason code.

    Short answer

    ITMS-91053 means your build references at least one Required Reason API without an entry in a PrivacyInfo.xcprivacy file. The fix is to add (or update) the privacy manifest in Xcode, list the named API category under NSPrivacyAccessedAPITypes, and pair it with one of Apple's approved reason codes. The warning email names the API category so you do not have to guess. According to Apple's privacy manifest documentation, the file is a property list shipped at the root of the app bundle, and each third-party SDK on Apple's list must ship its own.

    What you should know

    • The deadline already passed. Since May 1, 2024, App Store Connect rejects new submissions that touch a Required Reason API without declaring it.
    • The warning email names the category. Look for strings like NSPrivacyAccessedAPICategoryUserDefaults, NSPrivacyAccessedAPICategoryFileTimestamp, NSPrivacyAccessedAPICategorySystemBootTime, or NSPrivacyAccessedAPICategoryDiskSpace.
    • Each SDK declares its own usage. Your app manifest covers your code; framework manifests cover the framework's code. You cannot declare reasons on behalf of a third-party SDK.
    • The reason codes are short alphanumeric strings. Apple publishes the allowed list (examples: CA92.1, C617.1, 35F9.1, 1C8F.1). Custom strings are not accepted.
    • Builds for TestFlight can slip through. Some builds reach internal testers with only a warning, then fail when promoted to the store. Treat any warning as blocking.

    What is the Required Reason API list and why does Apple check for it?

    The short answer is that Apple keeps a list of system APIs that have been abused for device fingerprinting, and any call to one of those APIs has to be paired with a documented reason. The categories in scope today are file timestamp APIs, system boot time APIs, disk space APIs, active keyboard APIs, and NSUserDefaults. Each has its own approved reasons, and Apple's Describing use of required reason API page is the authoritative list.

    The check is automated and runs at upload time in App Store Connect. The reviewer machine scans the compiled binary, finds the symbols that map to Required Reason APIs, then looks for matching entries in every privacy manifest inside the app bundle (your app manifest plus one per included framework). If a symbol appears in the binary and no manifest declares it, App Store Connect emits ITMS-91053 with the missing category name. The check is symbol-based, not source-based, so Swift, Objective-C, Hermes-compiled JavaScript, and Flutter Dart all run through the same scanner once they reach the linker stage.

    In practice, very few apps trigger this for first-party code. The usual offender is a transitive dependency that has not been updated since May 2024.

    How do you decode the ITMS-91053 email into a fix?

    The email follows a stable shape. Apple lists the API category once, then the symbol once, then the framework that contains the symbol. A typical message reads: "ITMS-91053: Missing API declaration: Your app's code references one or more APIs that require reasons, including the following API categories: NSPrivacyAccessedAPICategoryUserDefaults."

    Three steps cover most cases.

    1. Open the email and write down each category named after "API categories:". There may be one, or there may be three or four. Each is a separate fix.
    2. For each category, decide whether it is your code or a dependency. Run nm -gU $(find . -name '*.framework' -o -name '*.xcframework') inside the Xcode build artifacts and grep for the matching symbol. NSUserDefaults maps to __NSUserDefaults and setObject:forKey:. File timestamp maps to stat, fstat, and getattrlist. System boot time maps to mach_absolute_time and clock_gettime. Disk space maps to statfs, volumeAvailableCapacity, and NSFileSystemFreeSize.
    3. If the symbol lives in your code, add the category to your top-level PrivacyInfo.xcprivacy with the matching reason code. If it lives in a third-party framework, update the dependency to a version that ships its own manifest, or replace it.

    The trap here is searching the source tree for the symbol name. Many of these calls live deep inside compiled .a static archives that ship with vendored SDKs, so grep on the source repo will return zero matches even when the binary clearly contains the call.

    How do you create and fill in PrivacyInfo.xcprivacy?

    In Xcode, choose File > New > File, type "privacy" in the filter, and pick App Privacy from the Resource list. Check the target you want to attach the file to, then click Create. Xcode writes a property list named PrivacyInfo.xcprivacy at the project root and adds it to the target's Copy Bundle Resources phase. As Antoine van der Lee's writeup on ITMS-91053 explains, the file ships at the root of the compiled app bundle and is the only place App Store Connect looks for first-party declarations.

    For each Required Reason API category in scope, add an entry under the NSPrivacyAccessedAPITypes key. Each entry is a dictionary with two keys: NSPrivacyAccessedAPIType (the category string) and NSPrivacyAccessedAPITypeReasons (an array of approved reason codes). The reason codes are short identifiers like CA92.1 for "access information about the file or directory created or modified by the user" or 1C8F.1 for "access user defaults that read and write information shared in an App Group." Apple publishes the full list of allowed reasons for each category in TN3183: Adding required reason API entries to your privacy manifest.

    A minimal manifest for an app that reads and writes NSUserDefaults inside an App Group, checks file timestamps for cache invalidation, and reads disk space for an offline mode looks like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>NSPrivacyAccessedAPITypes</key>
      <array>
        <dict>
          <key>NSPrivacyAccessedAPIType</key>
          <string>NSPrivacyAccessedAPICategoryUserDefaults</string>
          <key>NSPrivacyAccessedAPITypeReasons</key>
          <array><string>1C8F.1</string></array>
        </dict>
        <dict>
          <key>NSPrivacyAccessedAPIType</key>
          <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
          <key>NSPrivacyAccessedAPITypeReasons</key>
          <array><string>C617.1</string></array>
        </dict>
        <dict>
          <key>NSPrivacyAccessedAPIType</key>
          <string>NSPrivacyAccessedAPICategoryDiskSpace</string>
          <key>NSPrivacyAccessedAPITypeReasons</key>
          <array><string>85F4.1</string></array>
        </dict>
      </array>
    </dict>
    </plist>
    

    Rebuild, archive, and re-upload. The check runs again at upload time, and the ITMS-91053 message disappears once every named symbol has a matching declaration.

    Which APIs trigger which category?

    This is the mapping that saves the most time when reading the warning email. The categories, the underlying functions, and one common approved reason for each look like this.

    Category stringUnderlying APIs (symbols you will find with nm)Typical legitimate reasonSample reason code
    NSPrivacyAccessedAPICategoryUserDefaultsNSUserDefaults, setObject:forKey:, objectForKey:Read or write user preferences inside your own app or App Group1C8F.1
    NSPrivacyAccessedAPICategoryFileTimestampstat, fstat, getattrlist, NSFileCreationDate, NSURLContentModificationDateKeyDisplay file dates to the user or invalidate a local cacheC617.1
    NSPrivacyAccessedAPICategorySystemBootTimemach_absolute_time, clock_gettime with CLOCK_UPTIME_RAW, systemUptimeMeasure short intervals for performance instrumentation35F9.1
    NSPrivacyAccessedAPICategoryDiskSpacestatfs, statvfs, volumeAvailableCapacity, NSFileSystemFreeSizeWarn the user before downloading or writing a large file85F4.1
    NSPrivacyAccessedAPICategoryActiveKeyboardsUITextInputMode.activeInputModesProvide a feature that requires knowledge of the user's active keyboards (rare)3EC4.1

    The list is short because Apple kept the scope deliberately narrow. The full catalog of approved reasons is in TN3183 above; pick the one that matches how your code actually uses the API. Picking a reason that does not match (for example, claiming an analytics measurement reason for a UserDefaults call that is really storing a session token) is a Guideline 5.1.1 risk, not just a manifest hygiene risk.

    How do you handle missing manifests in third-party SDKs?

    The short answer is that you cannot fix a missing manifest from inside your app. The framework binary has to ship its own PrivacyInfo.xcprivacy at the root of its .framework or .xcframework bundle. If it does not, App Store Connect attributes the missing declaration to your app, even though the offending symbol lives in someone else's code.

    The practical path is to update. As documented in the Firebase iOS SDK privacy manifest discussion, Firebase 10.22.1 was the version that drew ITMS-91053 reports across analytics, Crashlytics, and Firestore. The fix shipped in subsequent releases, and most major SDKs (AppsFlyer, OneSignal, Sentry, Bugsnag, Adjust, Branch) followed the same pattern by mid-2024. If a small or stale SDK still has no manifest, raise an issue on the repo, pin a fork with the manifest added, or replace the dependency.

    For builders who want an external automated read of the binary before submission, PTKD.com (https://ptkd.com) is one of the platforms focused on pre-submission scanning aligned with OWASP MASVS for no-code and vibe-coded apps. The scan flags missing privacy manifests inside the IPA the same way App Store Connect does, but on demand and before the upload.

    What to watch out for

    A few details cost teams a resubmission cycle even after the manifest is added.

    First, the manifest has to be inside the compiled bundle, not just in the Xcode project. If the file is not added to the target's Copy Bundle Resources phase, the archive ships without it and App Store Connect emits the same warning. Verify the IPA after archiving: unzip it, then check that Payload/<AppName>.app/PrivacyInfo.xcprivacy exists and contains the expected keys.

    Second, CocoaPods and Carthage sometimes strip privacy manifests during dependency resolution if the podspec or Cartfile does not list the file as a resource. Pin to CocoaPods 1.15.2 or later, which added explicit support for shipping privacy manifests from pods. Run pod install again after the upgrade and confirm the file is present inside the framework bundle.

    Third, dynamic frameworks built with use_frameworks! need the manifest inside the framework binary, not loose in the Pods directory. The build step that copies the manifest into the framework runs only when the resource is declared correctly in the podspec.

    Fourth, the myth that turning off a feature avoids the check. Apple's scanner looks at symbols present in the binary. If the function is linked, the declaration is required, even if the code path is dead. Strip-unused symbol passes that depend on the linker (dead code stripping at the Swift level) help; conditional compilation that removes the import entirely is cleaner.

    Key takeaways

    • Read the email carefully. ITMS-91053 names the category in plain text; the fix starts there, not in your source tree.
    • Audit your dependencies first. Most ITMS-91053 reports trace to a vendored SDK that has not shipped its own PrivacyInfo.xcprivacy. Update or replace before you touch your own manifest.
    • Match reasons to actual usage. Approved reason codes like 1C8F.1, C617.1, 35F9.1, and 85F4.1 each map to a specific behavior; pick the one that describes what your code does.
    • Verify the manifest is in the IPA. Unzip the archive and confirm PrivacyInfo.xcprivacy is at the bundle root before resubmitting.
    • Some teams outsource the pre-submission scan. Platforms like PTKD.com (https://ptkd.com) check the compiled IPA for missing privacy manifests and Required Reason API mismatches before the build reaches App Store Connect, which shortens the loop on rejections like ITMS-91053.
    • #itms-91053
    • #privacy manifest
    • #app store connect
    • #required reason api
    • #ios
    • #privacyinfo.xcprivacy
    • #app review

    Frequently asked questions

    Is ITMS-91053 a rejection or a warning?
    Both, depending on the date and the build. Since May 1, 2024, App Store Connect treats Required Reason API issues as a hard rejection during submission to the store. Builds uploaded for TestFlight may still be accepted with the message surfacing only as a warning email. Either way, treat it as blocking, because the production release will fail review until the manifest is added.
    Do I need a PrivacyInfo.xcprivacy file for every SDK I use?
    You do not write one for each SDK. Each third-party SDK on Apple's commonly used list must ship its own PrivacyInfo.xcprivacy inside the framework. Your app needs a single top-level manifest for code you wrote. If an SDK is missing its manifest, update to a version that ships one or replace the SDK. Apple does not let you declare reasons on behalf of a dependency.
    What if my app does not use any of the named APIs directly?
    The ITMS-91053 email lists the symbol and the category, but the actual call usually lives inside a transitive dependency. Run nm or otool on the compiled framework binaries to find which library imports the symbol. Common culprits include older versions of Firebase, Sentry, AppsFlyer, OneSignal, and analytics SDKs that touch mach_absolute_time, statfs, or NSUserDefaults under the hood.
    Can I just declare every category to be safe?
    No. Apple expects an honest declaration that matches actual usage. Listing categories you do not use is a privacy disclosure issue and can trigger Guideline 5.1.1 review. Match the manifest to what the binary actually calls. If a future build adds a dependency that touches a new category, update the manifest at that point, not preemptively.
    Does this apply to React Native, Flutter, or FlutterFlow projects?
    Yes. Any framework that compiles to a native iOS binary, including React Native, Expo, Flutter, FlutterFlow, Capacitor, and KMP, goes through the same App Store Connect check. Recent versions of Flutter and React Native ship a default PrivacyInfo.xcprivacy in the iOS module, but builder-generated SDKs and older plugins often do not. Audit the Pods directory after every dependency update.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free