One Logo Pool Ball
wwwwwwwwwwwwwwwwwww

App Tracking

Request and inspect iOS App Tracking Transparency permission

One.AppTracking exposes the App Tracking Transparency status and the one-time permission request. Use it when your app needs permission for tracking across other companies’ apps or websites.

On iOS it reads ATTrackingManager and requests authorization on the main thread. On Android and web both methods return denied.

Usage

import { One } from 'one'
const before = One.AppTracking.getPermissionStatus()
if (before === 'notDetermined') {
const after = await One.AppTracking.requestPermission()
if (after === 'authorized') {
// start the tracking-dependent feature
}
}

The status is not determined, restricted, denied, or authorized. Requesting after the system has decided returns the current status without prompting again.

How it works

Add a non-empty NSUserTrackingUsageDescription to the iOS Info.plist before building via native.app.ios.infoPlist; without it the request rejects as a manifest error. Concurrent calls share the same request. The system prompts only while the app is active with no other permission prompt pending. An inactive app rejects the request; if iOS dismisses the prompt without a choice, the request returns not determined, so ask again once the app is active and other prompts have closed.

API reference

MethodsTypeDescription
getPermissionStatus() => AppTrackingPermissionStatusThe tracking status, without prompting.
() => AppTrackingPermissionStatusThe tracking status, without prompting.
requestPermission() => Promise<AppTrackingPermissionStatus>Ask once. Resolves with the resulting status.
() => Promise<AppTrackingPermissionStatus>Ask once. Resolves with the resulting status.

Platform differences

iOSAndroidWeb
EngineTracking hubNoneNone
StatusFour statesDeniedDenied
PromptOnceNeverNever

Limits and gotchas

Examples

Gate an analytics SDK

import { One } from 'one'
async function enableTracking(start: () => void) {
if (One.AppTracking.getPermissionStatus() !== 'notDetermined') return
const status = await One.AppTracking.requestPermission()
if (status === 'authorized') start()
}

The pre-check skips decided users without a wasted request. Only an explicit grant starts the tracking-dependent SDK.

Explain before asking

import { useState } from 'react'
import { Button, Text } from 'react-native'
import { One } from 'one'
function TrackingPrimer({ onDone }: { onDone: () => void }) {
const [asked, setAsked] = useState(false)
async function ask() {
setAsked(true)
await One.AppTracking.requestPermission()
onDone()
}
if (asked) return null
return (
<>
<Text>Personalized ads support free features. You can change this in Settings.</Text>
<Button title="Continue" onPress={ask} />
</>
)
}

A primer screen states the value before the system prompt appears, which is the only moment your own words can precede Apple’s. The component unmounts itself once the request settles.

Edit this page on GitHub.