Or try one:
Why the three have to agree
An iOS app now describes its data in three places: the privacy label in App Store Connect, the PrivacyInfo.xcprivacy file inside the build, and, if it is on Android too, the Data safety form in Play Console. Each is filled in by hand, usually months apart, and reviewers read them against each other and against the SDKs in the binary. A label that says “Data Not Collected” next to an ads SDK is the kind of mismatch that comes back as a rejection.
This works all three out from one set of answers. It knows what the common SDKs send, and asks you only what a dependency list can't show: whether your ads are personalized, whether people sign in, and whether anything they make leaves the phone.
What each SDK adds
What we declare in our own Flutter apps, all of which passed App Review and Play review with these answers. Read on 31 October 2026. SDKs change, so check each one's own disclosure page before you submit.
| SDK | App Store label | Play Data safety |
|---|---|---|
| Google Mobile Ads (AdMob) | Device ID, Advertising Data, Coarse Location, Product Interaction, Other Diagnostic Data, all for Third-Party Advertising | Device or other IDs, Approximate location, App interactions, Diagnostics. Shared. |
| Firebase Analytics | Product Interaction, Device ID, Other Diagnostic Data, for Analytics | App interactions, Device or other IDs, Diagnostics. Not shared. |
| Crashlytics or Sentry | Crash Data, Performance Data, Other Diagnostic Data, Device ID, for App Functionality | Crash logs, Diagnostics, Device or other IDs. Not shared. |
| In-app purchases or RevenueCat | Purchase History (and User ID with RevenueCat), linked to the user | Purchase history. Not shared. |
| Sign-in (Firebase Auth, Supabase, Google, Apple) | User ID, plus Email Address and Name if you keep them, linked to the user | User IDs, Email address, Name, for App functionality and Account management. |
“Shared” on Play is the answer people most often get wrong. Data sent to a company that processes it only for you, like Firebase, counts as collected, not shared. We mark only the AdMob rows as shared, because Google's AdMob disclosure guidance says what the ads SDK receives should be declared that way.
Tracking follows the ads, not the SDK. With personalized ads after the App Tracking Transparency prompt, Device ID and Advertising Data are used to track and NSPrivacyTracking is true. With non-personalized or child-directed ads they aren't. A kids' app should never show the tracking prompt at all, and on Android should remove the AD_ID permission the ads SDK merges in.
Required-reason APIs
Apple lists a few APIs that need a declared reason, because they can be used to fingerprint a device. Since 1 May 2024 an upload that uses one without a reason is refused with ITMS-91053: Missing API declaration. The ones a typical Flutter or React Native app reaches are:
NSPrivacyAccessedAPICategoryUserDefaults, reasonCA92.1: settings the app itself stored. Every Flutter app reaches this through the engine andshared_preferences; React Native through AsyncStorage and its settings module.NSPrivacyAccessedAPICategoryFileTimestamp, reasonC617.1: timestamps of files inside the app's own container, frompath_provider, sqflite, Hive orexpo-file-system.NSPrivacyAccessedAPICategoryDiskSpace, reasonE174.1: checking free space before writing, from device-info and disk-space plugins.
Most current plugins ship their own manifest that declares their use. Declaring the same category in your app's manifest as well is allowed, and it covers an older plugin that doesn't.
Questions
What is PrivacyInfo.xcprivacy?
A property list in your iOS app bundle that says what data the app collects, whether it tracks, and why it calls certain APIs Apple lists as needing a reason, such as UserDefaults and file timestamps. Since 1 May 2024, App Store Connect rejects uploads whose code uses one of those APIs without a declared reason.
What does ITMS-91053 Missing API declaration mean?
Your build calls a required-reason API, and neither your app's privacy manifest nor the SDK's own one gives a reason for it. The email names the category, for example NSPrivacyAccessedAPICategoryUserDefaults. Add that category with an approved reason code to your app's manifest, or update the SDK to a version that ships its own manifest.
Does a Flutter app need its own privacy manifest?
Yes. Flutter and most current plugins ship their own manifests, but your app's manifest is where you declare the data your app collects and whether it tracks. Apple builds the privacy report from all of them together.
Is Firebase data shared on the Google Play Data safety form?
Not when Firebase processes the data for you as a service provider, which Play does not count as sharing. Mark it collected, not shared. We mark the AdMob rows as shared, because Google's own AdMob guidance tells developers to.
Does showing AdMob ads mean my app tracks users?
Only if the ads are personalized using the advertising identifier. Then Device ID and Advertising Data are used for tracking, NSPrivacyTracking is true, and you need the App Tracking Transparency prompt. Non-personalized and child-directed ads do not track.
Do photos picked in my app count as collected?
Only if they leave the device. Apple and Google both count data as collected when it is sent off the phone. A photo that is only shown or edited on the device is not collected.
Catch it before release
Our App Compliance skill for Claude Code reads the whole app rather than the dependency list: AdMob consent that never asks, a sibling app's ad ids, a tracking prompt App Review can't reach, and a manifest that contradicts the code. It works with Flutter, React Native and Expo.
The store listing checker, the app-ads.txt checker and the iPhone Duo checker are free here too.