Privacy

    Why does ITMS-91053 say a provider is missing for UserDefaults?

    App Store Connect upload error referencing ITMS-91053 with a third-party framework listed as the missing provider for UserDefaults

    The processing email from App Store Connect names UserDefaults and your own code does not call it directly. The error is real, the missing provider is usually a third-party framework bundled inside the build, and the fix is either a manifest in the SDK or one extra entry in your own PrivacyInfo.xcprivacy.

    Short answer

    App Store Connect returns ITMS-91053 when the compiled binary references a required reason API without a matching declaration in a PrivacyInfo.xcprivacy file. For NSPrivacyAccessedAPICategoryUserDefaults, the provider missing the declaration is the target that ships the call, often a vendor framework rather than the app code itself. The fix is one of three approved reason codes (CA92.1, 1C8F.1, or C56D.1) inside a manifest, declared either in the SDK that ships the call or, when that is not possible, in your app's own manifest. Apple has enforced this rule for new App Store and TestFlight submissions since 1 May 2024, per the Apple Developer privacy manifest documentation.

    What you should know

    • ITMS-91053 reads the compiled Mach-O, not your Swift source. The audit detects symbols like NSUserDefaults, +standardUserDefaults, and initWithSuiteName regardless of which framework owns the call.
    • The word provider in the rejection email refers to whichever bundle ships the symbol. When the call sits inside a third-party SDK, that SDK is the provider, not your app target.
    • Apple publishes exactly three approved reason codes for UserDefaults. CA92.1 for in-app defaults, 1C8F.1 for App Group sharing, and C56D.1 for SDK wrappers.
    • SDKs on Apple's commonly used list must ship their own manifest and signature. Firebase, GoogleAds, the Facebook SDK, OneSignal, and many others appear on that published list.
    • The build number has to increment before App Store Connect re-ingests. Re-uploading the same number after fixing the manifest leaves the rejected binary in place.
    • An app-level manifest can cover a vendor call as a fallback. The cleaner fix is updating the SDK, because future audits expect the provider to declare its own use.

    Why does App Store Connect blame UserDefaults if my code does not call it?

    The audit pipeline scans every binary uploaded to App Store Connect for symbols that match the list of required reason APIs published by Apple. The UserDefaults category covers NSUserDefaults, the Swift UserDefaults wrapper, the +standardUserDefaults singleton, and the initWithSuiteName initializer. The scan reads the Mach-O, not the Swift or Objective-C source, so a clean grep across your repository can return zero hits while the upload still fails.

    The reason this surprises developers is that most modern apps embed dozens of frameworks. An analytics SDK reading a feature flag at startup, a crash reporter persisting a session token, or a routing library remembering the last viewed screen all sit inside frameworks linked into the app bundle. The symbol survives stripping because the framework actually invokes it. Apple's TN3183 technote is explicit that the audit is performed at API level rather than behavioural level, which is why the diagnostic arrives during ingestion rather than at runtime.

    The phrase missing provider in developer summaries refers to the bundle that should have shipped the corresponding NSPrivacyAccessedAPICategoryUserDefaults entry. The audit blames the call site, and the call site is whatever .framework or static archive holds the symbol. When that bundle is your app target, the fix sits in your own PrivacyInfo.xcprivacy. When it is a vendor framework, the cleaner answer is the SDK author.

    How do I find which framework is the missing provider?

    Open the archive in Finder and Show Package Contents. The .app folder contains a Frameworks directory with one .framework per embedded dependency. Each modern framework that uses a required reason API should ship a PrivacyInfo.xcprivacy at the root of its bundle. The frameworks that do not are the candidates.

    A faster pass is the command line:

    xcrun nm -u YourApp.app/Frameworks/SomeSDK.framework/SomeSDK \
      | grep -E "NSUserDefaults|standardUserDefaults"
    

    A non-empty result confirms the framework references the API. Running the same loop across each framework in Frameworks/ tells you which vendor needs a manifest. The approach is described in the Apple privacy manifest adoption guide.

    A second clue is Apple's list of SDKs that commonly use required reason APIs. If the build includes one of those by name (Firebase, GoogleSignIn, the Facebook SDK, OneSignal, Adjust, AppsFlyer, Branch, Sentry, Datadog, and others), upgrading to the version that ships a privacy manifest is almost always the right move. Apple flags this list as the SDKs whose binary signatures and manifests Xcode validates at archive time.

    Should I update the SDK or write the manifest myself?

    Updating the SDK is the right answer in most cases. The provider knows which reason codes match its calls, ships the entry inside its own bundle, and lets future audits keep working without your intervention. The OneSignal team, for example, shipped a privacy manifest in SDK 5.0.4 after community pressure, and Firebase rolled in privacy manifests across the iOS SDK starting with 10.23.0.

    When the SDK has not yet shipped a manifest, you have a fallback. App Store Connect accepts a manifest in the app target that covers calls actually made elsewhere in the binary. The ingestion audit only checks that one approved reason exists for the category somewhere in the upload. The trade-off is that the app maintainer takes on responsibility for keeping the declaration accurate as the SDK changes.

    Three situations argue against writing the manifest yourself. First, when the SDK is on Apple's published list, Xcode also validates a binary signature that the SDK author has to produce; a manifest in your app does not solve the signature requirement. Second, when several SDKs use UserDefaults under different reason codes, a single app-level CA92.1 hides the App Group case. Third, when the SDK eventually ships its own manifest, you carry duplicated declarations that drift apart over time.

    For builders who want an external read of a compiled IPA before the next upload, PTKD.com (https://ptkd.com) is one of the platforms set up specifically for pre-submission scans of the bundle. The report inspects each embedded framework for required reason API symbols and flags the ones missing a privacy manifest, which shortens the loop between rejection and a clean upload.

    Which reason code should I use for UserDefaults?

    Apple publishes three approved reasons under NSPrivacyAccessedAPICategoryUserDefaults. Each matches a different usage pattern, and a single manifest entry can list more than one when the binary legitimately spans cases.

    Reason codeWhen to use itTypical caller
    CA92.1Reading or writing defaults that stay inside the appApp target storing settings, feature flags, login state
    1C8F.1Defaults shared inside an App Group with widgets, extensions, watch app, or App ClipWidget reading a shared preference via initWithSuiteName
    C56D.1A third-party SDK wrapping UserDefaults behind a function the host app callsVendor framework persisting an installation identifier

    The most common code is CA92.1. A login flag stored under UserDefaults.standard, a saved theme preference, or a hide-onboarding key all sit here. The Apple page Describing use of required reason API lists CA92.1 as the catchall for app-only access.

    C56D.1 is the code that maps to the missing provider framing. The reason text restricts the use of derived information to operations on behalf of the host app and forbids the SDK from using the values for its own purposes. An app developer does not pick C56D.1 for first-party code; the code only makes sense when the declaring bundle is the SDK itself.

    What to watch out for

    The single most common loop is uploading a fixed binary with the old build number. App Store Connect treats the Invalid Binary as the binary for that build number and does not re-ingest a second upload at the same number. Increment the build number in the General tab of the target settings, archive, upload, and the audit runs against the new bundle.

    The second common loop is target membership. Adding PrivacyInfo.xcprivacy to the project navigator is not enough; the File Inspector has to show the app target checked under Target Membership. A manifest that sits in the project but outside the target never reaches the .app folder, and ITMS-91053 returns on the next upload.

    A myth worth retiring is that turning off UserDefaults in your own code clears the error. The compiled binary keeps the symbol whenever any linked framework references it. The fix lives in the manifest declaration, not in removing first-party calls.

    A final caveat is that App Store Connect does not police whether CA92.1 was the most accurate choice when 1C8F.1 would have fit better. The ingestion audit only checks that one approved reason exists for the category. Picking the reason that genuinely matches the call is still the safer practice because a later human reviewer can ask about it, and the Privacy Nutrition Label drawn from the manifest is shown publicly.

    Key takeaways

    • The provider in ITMS-91053 is whichever bundle ships the UserDefaults symbol; the audit reads the Mach-O, not your source.
    • Updating the SDK to a version that ships its own PrivacyInfo.xcprivacy is the cleanest fix; writing the manifest in your app is a fallback when the SDK lags.
    • CA92.1 covers in-app defaults, 1C8F.1 covers App Group sharing, and C56D.1 is reserved for SDKs wrapping the API behind a function the host app calls.
    • Increment the build number after every manifest edit, and confirm the manifest sits inside the target via Target Membership before each archive.
    • For builders who want an external automated scan of the compiled IPA before submission, PTKD.com is one of the platforms focused on the OWASP-aligned read across each embedded framework, which often surfaces the missing provider before App Store Connect does.
    • #itms-91053
    • #privacy manifest
    • #ios
    • #app store connect
    • #userdefaults
    • #third-party sdk
    • #required reason api

    Frequently asked questions

    Does removing my own UserDefaults calls clear ITMS-91053?
    No. The audit reads the compiled Mach-O and counts every symbol in every embedded framework. If an analytics or crash SDK still calls NSUserDefaults under the hood, the symbol survives stripping and the rejection returns on the next upload. The reliable fix is either updating that framework to a version that ships its own PrivacyInfo.xcprivacy or adding a CA92.1 entry to your app manifest that covers the call.
    Which third-party SDKs most often cause the UserDefaults flavour of ITMS-91053?
    The recurring names in developer threads are Firebase before 10.23.0, the Facebook SDK before April 2024 releases, GoogleSignIn under 7.1.0, OneSignal before 5.0.4, Adjust under 4.38.0, AppsFlyer under 6.12.2, and Branch under 3.0.0. Each shipped a privacy manifest in a later release. The cleanest fix is bumping to the version that includes PrivacyInfo.xcprivacy in its own bundle, then re-archiving with a higher build number.
    Can I keep the SDK pinned and still pass review by writing the manifest in my app target?
    Yes for ingestion, with caveats. App Store Connect accepts the category and reason code from anywhere in the upload, so a CA92.1 entry in your app manifest clears the audit even when the call lives inside a vendor framework. The risk is divergence: when the SDK eventually ships its own declaration, two manifests can drift, and the App Group case may go undeclared if you only listed CA92.1.
    Do I need a separate manifest for an App Group used by a widget?
    The widget target needs its own PrivacyInfo.xcprivacy if it reads or writes the shared defaults. Use reason code 1C8F.1 in both the app and the extension when they share the same suite name. Apple's audit checks each .appex bundle independently from the main .app, so a manifest in the app alone does not cover the symbols compiled into the extension binary.
    Will adding the manifest entry change the public App Store listing?
    The Privacy Nutrition Label on the listing reflects the data types declared in App Store Connect, not the required reason codes in the manifest. The manifest entry for UserDefaults is metadata read at ingestion and used by Apple to confirm that every required reason API in the bundle has an approved reason. The label keeps showing whatever was set under App Privacy.

    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