Skip to Content
Course content

246: App Tracking Transparency Implementation

Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you're planning to use any third-party analytics or ad networks that track users across other companies' apps and websites, you have to deal with App Tracking Transparency (ATT). It's not optional. If you submit an app that tracks users without this prompt, Apple will reject it faster than you can hit the upload button.

For this lesson, we're going to build a small "User Preferences" module for a hypothetical news app. The app wants to track the user's reading habits across other news sites to suggest better articles. Let's get this implemented.

Adding the justification to the plist

Before we write a single line of Swift code, we have to tell the system why we want this permission. If you don't provide a string for the user to read, the app will crash the moment you request authorization. I'll be honest: I actually forgot this during my last project and spent ten minutes staring at a crash log wondering why the ATTrackingManager was killing my process.

Open your Info.plist and add the key NSUserTrackingUsageDescription. I'm going to set the value to: "We use your activity across other apps to suggest news stories that actually match your interests." Be specific here; Apple's reviewers hate vague descriptions like "To improve user experience."

Requesting permission in Swift

Now for the logic. We need to import the AppTrackingTransparency framework. I like to wrap this logic in a dedicated service so my View Controllers don't get cluttered with permission boilerplate.

import AppTrackingTransparency
import AdSupport

class TrackingService {
    static let shared = TrackingService()
    
    func requestPermission() {
        ATTrackingManager.requestTrackingAuthorization { status in
            switch status {
            case .authorized:
                print("Permission granted! We can now access the IDFA.")
                // Here is where you'd initialize your ad SDKs
            case .denied:
                print("Permission denied. Using generic tracking.")
            case .notDetermined:
                print("The user hasn't been asked yet.")
            case .restricted:
                print("Permission restricted (e.g., parental controls).")
            @unknown default:
                print("Something unexpected happened.")
            }
        }
    }
}

The timing trap

Here is a subtle point that trips up a lot of developers. If you call requestPermission() inside viewDidLoad or init of your first screen, the prompt might never appear. Why? Because the app hasn't fully transitioned to the active state yet, and the system simply ignores the request.

I've found the most reliable way to handle this is to trigger the request when the app becomes active. In a modern SwiftUI app, you can use onChange(of: scenePhase). In a UIKit app, you'd typically do this in applicationDidBecomeActive. Let's use a simple approach for our news app by calling it slightly after the view appears:

// Inside your main view or coordinator
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
    TrackingService.shared.requestPermission()
}

That one-second delay is a bit of a "hack," but it ensures the app is fully in the foreground and the system is ready to present the alert. In a production app, I'd recommend showing your own "pre-prompt" screen first—a simple view explaining the value of tracking—before triggering the official system popup. Users are much more likely to hit "Allow" if they understand the benefit first.




📋 Practical Task

Implementing ATT for the 'FitTrack' Analytics Module

You are adding a new feature to a fitness app called 'FitTrack' that integrates with third-party health platforms. Your goal is to implement the App Tracking Transparency flow to ensure the app is compliant with App Store guidelines.

  • Add the NSUserTrackingUsageDescription key to your Info.plist with a descriptive message explaining that tracking is used to sync fitness data across platforms.
  • Create a TrackingManager singleton class that handles the ATTrackingManager.requestTrackingAuthorization call.
  • Implement a mechanism (such as a delayed call or a response to app state changes) to ensure the prompt appears only after the app has fully entered the foreground.
  • Print the resulting ATTrackingManager.AuthorizationStatus to the console so you can verify that 'Authorized', 'Denied', and 'Restricted' states are handled correctly.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.