Rejected for guideline 5.1.2: what it means and how to find it

The notice names a guideline and not a file. Three checks that find the cause in a minute instead of a day.

Your build was rejected on a Monday. The notice names guideline 5.1.2 and nothing else. It does not say which file, which SDK, or which line. Somebody on your team now spends a day finding out, and the release date moves. Here is what that notice usually means, and how to find the cause in minutes rather than in a day. What 5.1.2 actually asks Apple's guideline 5.1.2 covers data use and sharing. The rejection you get for it is almost always one specific thing: your app reads the advertising identifier without asking permission first. Two files decide it. Info.plist has to carry NSUserTrackingUsageDescription . That string is what the system shows a person when the prompt appears. Without it the prompt cannot appear, and iOS returns a zeroed identifier rather than the real one. Your code has to call requestTrackingAuthorization before anything reads the identifier. Not at the same time. Before. Why the SDK is usually the cause The part that costs a day is that your own code often does neither of these. An analytics or attribution SDK does, inside a framework you did not write and cannot read. AppsFlyer, Adjust, Branch, Firebase, and most ad networks all read the identifier when they start. Several of them start themselves from application :didFinishLaunchingWithOptions: through a swizzled method, so there is no call in your source to find by searching. That is why bisecting SDKs is the usual approach, and why it takes a day. Three checks that take a minute Check the plist first. If NSUserTrackingUsageDescription is missing and any dependency touches tracking, that is the whole answer. plutil -p ios/Runner/Info.plist | grep -i tracking Check what you link. The lockfile names every SDK the build resolves. Read it rather than the import statements, because a transitive pod does not appear in your source at all. grep -iE "appsflyer|adjust|branch|firebase-analytics|facebook" Podfile.lock Check the order. If the usage string is there and you still got rejected, something reads the identifier before the prompt resolves. An SDK started in didFinishLaunchingWithOptions runs before a prompt that is requested in a view controller. The part people get wrong Adding the usage string alone does not fix it. The string makes the prompt possible. Something still has to ask. A build that carries the string and never calls requestTrackingAuthorization reads as tracking without consent, which is the same rejection with a different sentence attached. Catching it before you submit Every check above is mechanical. A file either has a key or it does not, and a lockfile either names a package or it does not. That means it belongs in your pull request rather than in a reply from review two weeks later. Peko runs those checks on every pull request, names the file and the line, and says which SDK it came from. The lint tier runs on your own machine, costs nothing, and needs no account.