> ## Documentation Index
> Fetch the complete documentation index at: https://docs.appdna.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# iOS Push Notifications

> Register tokens, handle delivery and taps

<Info>
  **Supported on:** iOS SDK `1.0.61+`
</Info>

The AppDNA SDK provides a complete push notification module for registering device tokens, handling notification delivery, and tracking user interactions.

## APNs Setup

Before using push notifications, configure Apple Push Notification service (APNs) for your app:

1. In Xcode, enable the **Push Notifications** capability under your target's **Signing & Capabilities** tab.
2. Generate an APNs authentication key (.p8 file) in the [Apple Developer Portal](https://developer.apple.com/account/resources/authkeys/list).
3. Upload the .p8 key to the AppDNA Console under **Settings > Push > iOS Configuration**.

<Warning>
  Without the APNs capability enabled and the .p8 key uploaded to the Console, push notifications will not be delivered to your users.
</Warning>

## Request Permission

Request push notification permission from the user. This presents the system permission dialog and registers for remote notifications:

```swift theme={null}
let granted = await AppDNA.registerForPush()

if granted {
    print("Push permission granted")
} else {
    print("Push permission denied")
}
```

The method returns a `Bool` indicating whether the user granted permission.

## Set Token Manually

If you handle token registration yourself (e.g., in `application(_:didRegisterForRemoteNotificationsWithDeviceToken:)`), pass the raw token data to the SDK:

```swift theme={null}
func application(
    _ application: UIApplication,
    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
    AppDNA.setPushToken(deviceToken)
}
```

## Set Permission Status

Manually update the SDK with the current push permission status:

```swift theme={null}
AppDNA.setPushPermission(granted: true)
```

## Track Delivery and Taps

Track when a push notification is delivered to the device:

```swift theme={null}
AppDNA.trackPushDelivered(pushId: "push-123")
```

Track when a user taps on a push notification:

```swift theme={null}
AppDNA.trackPushTapped(pushId: "push-123", action: "open_workout")
```

## Push Module

Access the push module directly for advanced usage:

```swift theme={null}
let pushModule = AppDNA.pushModule
```

<Note>
  On iOS the host-facing property is `AppDNA.pushModule` (Swift); Android, Flutter, and React Native expose the same surface as `AppDNA.push`. The behavior and methods are identical — only the namespace name differs. (On iOS there is also an internal `AppDNA.push` accessor for the lower-level `PushTokenManager`, but it is not part of the public API and hosts do not call it.)
</Note>

### PushModule Methods

| Method              | Signature                                      | Description                                                   |
| ------------------- | ---------------------------------------------- | ------------------------------------------------------------- |
| `requestPermission` | `requestPermission() async -> Bool`            | Request push permission and register for remote notifications |
| `token`             | `token: String?`                               | The current APNs device token as a hex string                 |
| `getToken`          | `getToken() -> String?`                        | Returns the current device token                              |
| `setDelegate`       | `setDelegate(_ delegate: AppDNAPushDelegate?)` | Set a delegate for push notification callbacks                |

## AppDNAPushDelegate Protocol

All 3 methods on this delegate fire from the SDK's push pipeline:

* `onPushTokenRegistered(token:)` — fires whenever the SDK registers a new APNs token (or detects a change). Token registration with the AppDNA backend continues regardless of whether you implement this method.
* `onPushReceived(notification:, inForeground:)` — fires when a push arrives.
* `onPushTapped(notification:, actionId:)` — fires when the user taps a notification or one of its action buttons.

Implement the `AppDNAPushDelegate` protocol to receive push notification lifecycle callbacks:

```swift theme={null}
protocol AppDNAPushDelegate {
    func onPushTokenRegistered(token: String)
    func onPushReceived(notification: PushPayload, inForeground: Bool)
    func onPushTapped(notification: PushPayload, actionId: String?)
}
```

### Example Implementation

```swift theme={null}
class MyPushHandler: AppDNAPushDelegate {
    func onPushTokenRegistered(token: String) {
        print("Token registered: \(token)")
    }

    func onPushReceived(notification: PushPayload, inForeground: Bool) {
        if inForeground {
            // Show in-app notification banner
            showBanner(title: notification.title, body: notification.body)
        }
    }

    func onPushTapped(notification: PushPayload, actionId: String?) {
        if let action = notification.action {
            // Handle deep link or custom action
            handleAction(action)
        }
    }
}

// Set the delegate
AppDNA.pushModule.setDelegate(MyPushHandler())
```

## PushPayload

The `PushPayload` struct contains the notification content:

| Property   | Type             | Description                            |
| ---------- | ---------------- | -------------------------------------- |
| `pushId`   | `String`         | Unique identifier for the notification |
| `title`    | `String`         | Notification title                     |
| `body`     | `String`         | Notification body text                 |
| `imageUrl` | `String?`        | URL to a rich notification image       |
| `data`     | `[String: Any]?` | Custom data payload                    |
| `action`   | `PushAction?`    | Action to perform when tapped          |

## PushAction

The `PushAction` struct defines the action associated with a notification tap:

| Property | Type     | Description                                       |
| -------- | -------- | ------------------------------------------------- |
| `type`   | `String` | Action type (e.g., "deep\_link", "url", "screen") |
| `value`  | `String` | Action value (e.g., a URL or screen identifier)   |

## Auto-Tracked Events

The SDK automatically tracks the following push-related events:

| Event                     | Triggered When                          |
| ------------------------- | --------------------------------------- |
| `push_token_registered`   | Device token is successfully registered |
| `push_permission_granted` | User grants push permission             |
| `push_permission_denied`  | User denies push permission             |
| `push_delivered`          | A push notification is delivered        |
| `push_tapped`             | User taps on a push notification        |

<Info>
  Auto-tracked events are sent alongside any manually tracked events. You do not need to track these events yourself.
</Info>

## Full Example

```swift theme={null}
import AppDNASDK

class AppDelegate: UIResponder, UIApplicationDelegate {
    let pushHandler = MyPushHandler()

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        AppDNA.configure(
            apiKey: "adn_live_xxx",
            environment: .production
        )

        AppDNA.pushModule.setDelegate(pushHandler)

        Task {
            let granted = await AppDNA.registerForPush()
            print("Push permission: \(granted)")
        }

        return true
    }

    func application(
        _ application: UIApplication,
        didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
    ) {
        AppDNA.setPushToken(deviceToken)
    }
}
```

<Note>
  For Notification Service Extension support (rich notifications, delivery tracking in background), see the [Offline Support](/sdks/ios/offline) guide for details on how events are queued and delivered.
</Note>
