# App Tracking Transparency (ATT) (/docs/sdk/att)



ATT is Apple's opt-in dialog for cross-app tracking. It gates IDFA
access. The Layers SDK does NOT auto-prompt; you decide when.

## When to prompt [#when-to-prompt]

Best practice: prompt when the user has seen enough value to understand
why you're asking. Not on first launch.

Common timings:

* After completing onboarding (3–5 screens in).
* Before a feature that benefits from personalization.
* Alongside (or just after) a paywall.

## Prompting from React Native [#prompting-from-react-native]

`@layers/react-native` ships a native module that wraps
`requestTrackingAuthorization`:

```ts
import Layers from '@layers/react-native';

await Layers.requestTracking();
// or
const status = await Layers.att.request();
// 'authorized' | 'denied' | 'restricted' | 'not_determined'
```

`Info.plist` still needs the usage description. With `@layers/expo` the
config plugin takes it as a parameter:

```json
["@layers/expo", {
  "appId": "app_xxx",
  "iosUserTrackingUsageDescription": "We use this to personalize your experience."
}]
```

Without Expo, add it manually:

```xml
<key>NSUserTrackingUsageDescription</key>
<string>We use this to personalize your experience.</string>
```

## Status behaviors [#status-behaviors]

| ATT status       | `idfa` forwarded to Meta CAPI? | CAPI still fires? |
| ---------------- | ------------------------------ | ----------------- |
| `authorized`     | Yes (plaintext in `madid`)     | Yes               |
| `denied`         | No                             | Yes               |
| `restricted`     | No                             | Yes               |
| `not_determined` | No                             | Yes               |

The relay continues to forward events via IP, UA, `install_id`, and any
advanced-matching fields you sent; match rates just drop without IDFA.

## Web / non-iOS platforms [#web--non-ios-platforms]

ATT is iOS-only. Calling `Layers.att.request()` on other platforms is a
no-op or returns `authorized` / platform-equivalent values.

## Native iOS SDK [#native-ios-sdk]

There is no native Swift SDK yet, so prompting from Swift code directly
via `ATTrackingManager.requestTrackingAuthorization` is currently
outside the Layers SDK surface. Pass the resulting status through the
React Native or Expo SDK if you need it to round-trip to the server.

## Don't ask twice [#dont-ask-twice]

iOS only shows the prompt once per install. If you call `requestTracking`
after a decision has been made, the OS returns immediately without
displaying the dialog. Deep-link to Settings if the user wants to change
their mind:

```ts
import { Linking } from 'react-native';
Linking.openSettings();
```
