Skip to main content

App Tracking Transparency (ATT)

ATT is Apple's privacy framework that requires apps to request user permission before accessing the IDFA. This is required for iOS 14.5+.

Prerequisites

  • iOS 14.5 or later
  • Apptrove .NET MAUI SDK installed

Implementation

Step 1: Add Permission Description

Add to Platforms/iOS/Info.plist:

<key>NSUserTrackingUsageDescription</key>
<string>This identifier will be used to deliver personalized ads to you.</string>

Step 2: Create ATT Helper (Platforms/iOS/AppTrackingHelper.cs)

using AppTrackingTransparency;
using AdSupport;
using Foundation;
using UIKit;

namespace YourApp.Platforms.iOS;

public static class AppTrackingHelper
{
public static async Task<string?> RequestTrackingAuthorizationAsync()
{
var status = ATTrackingManager.TrackingAuthorizationStatus;

if (status == ATTrackingManagerAuthorizationStatus.Authorized)
{
return GetIdfa();
}

if (status == ATTrackingManagerAuthorizationStatus.NotDetermined)
{
// Wait for app to be active
await WaitForAppToBeActiveAsync();

var tcs = new TaskCompletionSource<ATTrackingManagerAuthorizationStatus>();

ATTrackingManager.RequestTrackingAuthorization((newStatus) =>
{
tcs.TrySetResult(newStatus);
});

var result = await tcs.Task;

if (result == ATTrackingManagerAuthorizationStatus.Authorized)
{
return GetIdfa();
}
}

return null;
}

private static async Task WaitForAppToBeActiveAsync()
{
var app = UIApplication.SharedApplication;
int attempts = 0;

while (app.ApplicationState != UIApplicationState.Active && attempts < 30)
{
await Task.Delay(100);
attempts++;
}
}

public static string? GetIdfa()
{
if (ATTrackingManager.TrackingAuthorizationStatus == ATTrackingManagerAuthorizationStatus.Authorized)
{
var idfa = ASIdentifierManager.SharedManager.AdvertisingIdentifier.AsString();
if (!string.IsNullOrEmpty(idfa) && idfa != "00000000-0000-0000-0000-000000000000")
{
return idfa;
}
}
return null;
}

public static string GetTrackingStatusString()
{
return ATTrackingManager.TrackingAuthorizationStatus switch
{
ATTrackingManagerAuthorizationStatus.NotDetermined => "Not Determined",
ATTrackingManagerAuthorizationStatus.Restricted => "Restricted",
ATTrackingManagerAuthorizationStatus.Denied => "Denied",
ATTrackingManagerAuthorizationStatus.Authorized => "Authorized",
_ => "Unknown"
};
}
}

Step 3: Initialize SDK with ATT (App.xaml.cs)

Important

Call WaitForATTUserAuthorization() before Initialize() to ensure the SDK waits for the user's ATT decision.

using AppTroveSDK.Maui;

public partial class App : Application
{
public static string? Idfa { get; private set; }

public static async Task InitializeSDKAsync()
{
// On iOS, request ATT first
if (OperatingSystem.IsIOS())
{
Idfa = await RequestATTAsync();
Console.WriteLine($"ATT complete, IDFA = {Idfa ?? "null"}");
}

var config = new AppTroveSDKConfig("your-sdk-key", AppTroveEnvironment.Production);

// Wait for ATT user authorization (30 seconds timeout)
AppTroveSDK.WaitForATTUserAuthorization(30);

// Initialize SDK
AppTroveSDK.Initialize(config);
}

private static Task<string?> RequestATTAsync()
{
#if IOS
return Platforms.iOS.AppTrackingHelper.RequestTrackingAuthorizationAsync();
#else
return Task.FromResult<string?>(null);
#endif
}
}

Visual Examples

ATT Permission Dialog:

ATT Permission Dialog

IDFA Console Logs:

IDFA Access

IDFA Panel in Apptrove Dashboard:

IDFA Panel Details

ATT Status Values

StatusDescriptionSDK Behavior
AuthorizedUser granted permissionFull tracking enabled, IDFA available
DeniedUser denied permissionLimited tracking, no IDFA
RestrictedSystem restrictedLimited tracking, no IDFA
NotDeterminedNot requested yetWait for user decision

Troubleshooting

IssueSolution
ATT dialog not showingEnsure NSUserTrackingUsageDescription is in Info.plist
IDFA is nullCheck user granted permission and device supports IDFA
IDFA shows all zerosUser denied permission or running on simulator
SDK issuesCall WaitForATTUserAuthorization before Initialize

For support, contact support@trackier.com.