App Tracking Transparency (ATT)
This guide provides comprehensive instructions for implementing Apple's App Tracking Transparency (ATT) framework with the Trackier iOS SDK. ATT is required for iOS 14.5+ apps that want to access the Identifier for Advertisers (IDFA) for accurate attribution and tracking.
Overview
App Tracking Transparency (ATT) is Apple's privacy framework that requires apps to request user permission before accessing the IDFA. This is crucial for accurate attribution and tracking on iOS 14.5 and later.
Prerequisites
- iOS 14.5 or later
- Xcode 12.0 or later
- Trackier iOS SDK installed
- Access to your app's
Info.plist
file
Implementation
Step 1: Add Permission Description
Add the following key-value pair to your Info.plist
to describe why your app needs tracking permission:
<key>NSUserTrackingUsageDescription</key>
<string>We use tracking to personalize your experience and improve our services.</string>
Step 2: Create AppTrackingService Class
Create a dedicated service class to handle ATT permissions. This provides better organization and reusability:
import Foundation
import AppTrackingTransparency
import AdSupport
class AppTrackingService: ObservableObject {
@Published var trackingStatus: ATTrackingManager.AuthorizationStatus = .notDetermined
static let shared = AppTrackingService()
private init() {
updateTrackingStatus()
}
func updateTrackingStatus() {
trackingStatus = ATTrackingManager.trackingAuthorizationStatus
}
func requestTrackingPermission() {
// Check if we can request permission
guard ATTrackingManager.trackingAuthorizationStatus == .notDetermined else {
print("ATT permission already determined: \(ATTrackingManager.trackingAuthorizationStatus)")
return
}
ATTrackingManager.requestTrackingAuthorization { [weak self] status in
DispatchQueue.main.async {
self?.trackingStatus = status
self?.handleTrackingPermissionResponse(status: status)
}
}
}
private func handleTrackingPermissionResponse(status: ATTrackingManager.AuthorizationStatus) {
switch status {
case .authorized:
print("App Tracking Permission: Authorized")
// User granted permission, tracking is now allowed
// The Trackier SDK will automatically start tracking
// You can now access IDFA if needed
if let idfa = self.idfa {
print("IDFA: \(idfa)")
}
case .denied:
print("App Tracking Permission: Denied")
// User denied permission, tracking is not allowed
// The Trackier SDK will handle this gracefully
case .restricted:
print("App Tracking Permission: Restricted")
// Tracking is restricted (e.g., parental controls)
case .notDetermined:
print("App Tracking Permission: Not Determined")
// Permission hasn't been requested yet
@unknown default:
print("App Tracking Permission: Unknown status")
}
}
var canTrack: Bool {
return trackingStatus == .authorized
}
var idfa: String? {
guard canTrack else { return nil }
return ASIdentifierManager.shared().advertisingIdentifier.uuidString
}
}
Step 3: Update Your App's Main File
Important: Always include TrackierSDK.waitForATTUserAuthorization(timeoutInterval: 20)
before initializing the SDK. This ensures the SDK waits for the user's ATT decision before starting tracking, which is required for accurate attribution on iOS 14.5+. You can adjust the timeout value (20 seconds) according to your use case or logic.
Update your main app file (e.g., AppDelegate.swift
or App.swift
) to integrate ATT with the Trackier SDK:
import UIKit
import trackier_ios_sdk
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
private let trackingService = AppTrackingService.shared
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Initialize Trackier SDK with ATT support
initializeTrackierSDK()
// Request tracking permission after a short delay
requestTrackingPermissionIfNeeded()
return true
}
private func initializeTrackierSDK() {
// Create SDK configuration
let config = TrackierSDKConfig(
appToken: "YOUR_SDK_TOKEN_HERE", // Replace with your actual SDK token
env: TrackierSDKConfig.ENV_DEVELOPMENT
)
// Wait for ATT authorization before initializing SDK
TrackierSDK.waitForATTUserAuthorization(timeoutInterval: 20)
// Initialize the SDK
TrackierSDK.initialize(config: config)
// Configure conversion values after initialization
TrackierSDK.updatePostbackConversion(fineValue: 0, coarseValue: "low")
}
private func requestTrackingPermissionIfNeeded() {
// Check if ATT is available (iOS 14.5+)
if #available(iOS 14.5, *) {
// Request tracking permission after a short delay to ensure the app is fully loaded
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
if self.trackingService.trackingStatus == .notDetermined {
self.trackingService.requestTrackingPermission()
}
}
} else {
print("ATT not available on this iOS version")
}
}
}
Step 4: For SwiftUI Apps
If you're using SwiftUI, update your main app file:
import SwiftUI
import trackier_ios_sdk
@main
struct YourApp: App {
@StateObject private var trackingService = AppTrackingService.shared
init() {
initializeTrackierSDK()
}
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(trackingService)
.onAppear {
requestTrackingPermissionIfNeeded()
}
}
}
private func initializeTrackierSDK() {
let config = TrackierSDKConfig(
appToken: "YOUR_SDK_TOKEN_HERE", // Replace with your actual SDK token
env: TrackierSDKConfig.ENV_DEVELOPMENT
)
// Wait for ATT authorization before initializing SDK
TrackierSDK.waitForATTUserAuthorization(timeoutInterval: 20)
// Initialize the SDK
TrackierSDK.initialize(config: config)
// Configure conversion values after initialization
TrackierSDK.updatePostbackConversion(fineValue: 0, coarseValue: "low")
}
private func requestTrackingPermissionIfNeeded() {
// Check if ATT is available (iOS 14.5+)
if #available(iOS 14.5, *) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
if trackingService.trackingStatus == .notDetermined {
trackingService.requestTrackingPermission()
}
}
} else {
print("ATT not available on this iOS version")
}
}
}
Key Features
waitForATTUserAuthorization(timeoutInterval: 20)
: This method waits for the user to respond to the ATT prompt before initializing the SDK. The timeout can be adjusted based on your app's needs.- Automatic Status Handling: The service automatically handles all ATT status responses.
- IDFA Access: Provides easy access to IDFA when permission is granted.
- ObservableObject: Integrates seamlessly with SwiftUI for reactive UI updates.
Always replace "YOUR_SDK_TOKEN_HERE"
with your actual SDK token from the Trackier Panel. Using an incorrect token will cause attribution issues.
Visual Examples
ATT Permission Dialog:

IDFA Console Logs:
IDFA Panel in Trackier Dashboard: When tracking is properly configured with ATT, you can see the IDFA details in the Trackier panel for installs and events:
This panel shows the IDFA information when users grant tracking permission, allowing for accurate attribution and detailed tracking analytics.
ATT Status Values
Status | Description | SDK Behavior |
---|---|---|
.authorized | User granted permission | Full tracking enabled, IDFA available |
.denied | User denied permission | Limited tracking, no IDFA |
.restricted | System restricted (parental controls) | Limited tracking, no IDFA |
.notDetermined | Permission not requested yet | Wait for user decision |
Best Practices
- Timing: Request permission after app launch (1-2 second delay)
- User Experience: Explain why tracking is needed before requesting permission
- Timeout Configuration: Adjust timeout based on your app's flow (default 20 seconds)
- Status Monitoring: Monitor tracking status changes and update UI accordingly
- Check Status First: Always check if permission has already been determined before requesting
- Handle All Cases: Implement proper handling for all ATT status values
- iOS Version Check: Always check if ATT is available before using it
Troubleshooting
Common Issues
ATT Permission Not Requested
- Ensure
NSUserTrackingUsageDescription
is added toInfo.plist
- Check that the app targets iOS 14.5 or later
- Verify the permission request is called after app launch
IDFA Not Available
- Check if user granted permission (status should be
.authorized
) - Ensure the device supports IDFA (not available on simulator)
- Verify the app is not restricted by parental controls
SDK Initialization Issues
- Make sure
waitForATTUserAuthorization
is called before SDK initialization - Check that the timeout value is appropriate for your app flow
- Verify the SDK token is correct
Debug Tips
// Check current tracking status
let status = ATTrackingManager.trackingAuthorizationStatus
print("Current ATT Status: \(status)")
// Check if IDFA is available
if let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString {
print("IDFA: \(idfa)")
} else {
print("IDFA not available")
}
Support
For technical support and questions:
- Support Email: support@trackier.com
- Documentation: Trackier Documentation Portal
This guide provides comprehensive implementation of App Tracking Transparency with the Trackier iOS SDK, ensuring compliance with Apple's privacy requirements while maintaining accurate attribution and tracking capabilities.