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

# OSNotification payload

> Reference for OneSignal's OSNotification object, including all payload fields, Android and iOS-specific properties, custom data, and click actions.

The `OSNotification` class represents the push notification payload in OneSignal's SDKs. Use it to access notification title, body, custom data, and platform-specific properties when handling notifications in your app.

<Info>
  Push notification payloads are limited to `4096` bytes. To avoid truncation, keep payloads under `3500` bytes. The `additionalData` field is limited to `2048` bytes.
</Info>

***

## Accessing `OSNotification` in your app

All OneSignal SDKs provide notification events that return an `OSNotification` object:

* **Android**: Use the [foreground lifecycle listener](./mobile-sdk-reference#addforegroundlifecyclelistener-push), the [click listener](./mobile-sdk-reference#addclicklistener-push), or a [Notification Service Extension](./service-extensions)
* **iOS**: Use the [foreground lifecycle listener](./mobile-sdk-reference#addforegroundlifecyclelistener-push), the [click listener](./mobile-sdk-reference#addclicklistener-push), or a `UNNotificationServiceExtension`

This example reads the notification and a custom `promo_code` value from `additionalData` inside a click listener:

<CodeGroup>
  ```kotlin Kotlin theme={null}
  OneSignal.Notifications.addClickListener { event ->
    val notification = event.notification
    val promoCode = notification.additionalData?.optString("promo_code", null)
    // Use notification.title, notification.body, or promoCode
  }
  ```

  ```swift Swift theme={null}
  func onClick(event: OSNotificationClickEvent) {
    let notification = event.notification
    let promoCode = notification.additionalData?["promo_code"] as? String
    // Use notification.title, notification.body, or promoCode
  }
  ```

  ```javascript React Native theme={null}
  OneSignal.Notifications.addEventListener('click', (event) => {
    const { title, body, additionalData } = event.notification;
    const promoCode = additionalData?.promo_code;
    // Use title, body, or promoCode
  });
  ```

  ```dart Flutter theme={null}
  OneSignal.Notifications.addClickListener((event) {
    final notification = event.notification;
    final promoCode = notification.additionalData?['promo_code'];
    // Use notification.title, notification.body, or promoCode
  });
  ```

  ```csharp Unity (C#) theme={null}
  OneSignal.Notifications.Clicked += (sender, e) => {
    var data = e.Notification.AdditionalData;
    if (data != null && data.ContainsKey("promo_code")) {
      var promoCode = data["promo_code"].ToString();
    }
  };
  ```
</CodeGroup>

For the full listener API including Java, Objective-C, and Cordova/Ionic, see [`addClickListener()` Push](./mobile-sdk-reference#addclicklistener-push).

***

## Payload fields

<Note>
  The Android and iOS tables below list the native field names. Cross-platform SDKs expose the same payload with language-specific casing. Flutter uses `launchUrl` instead of `launchURL`, and the Unity C# SDK uses PascalCase, such as `AdditionalData` and `LaunchURL`.
</Note>

### Android fields

Access these as properties in Kotlin (`notification.title`) or as getters in Java (`notification.getTitle()`).

| Property | Type | Description |
| - | :-: | - |
| `body` | `String` | Body text of the notification. |
| `title` | `String` | Title of the notification. |
| `launchURL` | `String` | URL opened when the notification is clicked. |
| `notificationId` | `String` | OneSignal notification UUID. |
| `additionalData` | `JSONObject` | Custom key-value data set via dashboard or REST API. Max 2048 bytes. |
| `templateId` | `String` | Template UUID, if sent using templates. |
| `templateName` | `String` | Template name, if sent using templates. |
| `androidNotificationId` | `int` | Android native notification ID. |
| `largeIcon` | `String` | URL or resource name of large icon. |
| `smallIcon` | `String` | Small icon resource name. |
| `smallIconAccentColor` | `String` | Icon accent color in ARGB format. |
| `bigPicture` | `String` | URL of the big picture image. |
| `sound` | `String` | Sound resource name played. |
| `collapseId` | `String` | Collapse key for notification replacement. |
| `priority` | `int` | Android priority (-2 to 2). |
| `ledColor` | `String` | LED color in ARGB format. |
| `lockScreenVisibility` | `int` | Lock screen visibility: `1 = public`, `0 = private`, `-1 = secret`. |
| `fromProjectNumber` | `String` | Sender project number. |
| `sentTime` | `long` | When the notification was sent, as a Unix timestamp in seconds. |
| `ttl` | `int` | TTL (time-to-live) of the notification in seconds. |
| `groupedNotifications` | `List<INotification>` | Notifications included in a summary. |
| `groupKey` | `String` | Group key used in summaries. |
| `groupMessage` | `String` | Summary text. |
| `backgroundImageLayout` | `BackgroundImageLayout` | Deprecated. Background image layout and text colors. Not applicable on Android 12+. |
| `actionButtons` | `List<IActionButton>` | Action buttons, each with `id`, `text`, and `icon`. |
| `rawPayload` | `String` | Full raw JSON string of the payload. |

### iOS fields

| Property | Type | Description |
| - | :-: | - |
| `body` | `NSString` | Body text of the notification. |
| `title` | `NSString` | Title of the notification. |
| `launchURL` | `NSString` | URL opened when the notification is clicked. |
| `notificationId` | `NSString` | OneSignal notification UUID. |
| `additionalData` | `Dictionary` | Custom key-value `data` set via dashboard or REST API. Max 2048 bytes. |
| `templateId` | `NSString` | Template UUID, if sent using templates. |
| `templateName` | `NSString` | Template name, if sent using templates. |
| `subtitle` | `NSString` | Subtitle text. |
| `sound` | `NSString` | Sound file played. Defaults to the system sound. |
| `category` | `NSString` | iOS category identifier. Overrides OneSignal's `actionButtons`. |
| `threadId` | `NSString` | Used to group notifications into threads (iOS 10+). |
| `collapseId` | `NSString` | Collapse ID for notification replacement. |
| `badge` | `NSInteger` | Absolute badge value. |
| `badgeIncrement` | `NSInteger` | Amount to increment the badge. |
| `hasBadge` | `BOOL` | `true` if the notification sets a badge value. Use this to distinguish no badge from a badge of `0`. |
| `contentAvailable` | `BOOL` | If `content-available=1`, triggers background fetch. |
| `mutableContent` | `BOOL` | If `mutable-content=1`, triggers a Notification Service Extension. |
| `attachments` | `NSDictionary` | Rich media attachments (iOS 10+). |
| `relevanceScore` | `NSNumber` | Relevance score for notification summaries (iOS 15+). |
| `interruptionLevel` | `NSString` | Interruption level (iOS 15+). |
| `actionButtons` | `NSArray` | iOS action buttons. |
| `rawPayload` | `NSDictionary` | Full raw JSON of the payload. |

The iOS class also provides `parseWithApns`, a method that converts a raw APNs payload into an `OSNotification`. Use it inside a `UNNotificationServiceExtension`. See [Mobile Service Extensions](./service-extensions).

***

## Notification click events

Click listeners receive a click event with two properties: the `notification` object described above, and a `result` describing what the user clicked. Register a listener with [`addClickListener()`](./mobile-sdk-reference#addclicklistener-push). The event class is `INotificationClickEvent` on Android and `OSNotificationClickEvent` on iOS.

| Property | Type | Description |
| - | :-: | - |
| `notification` | `OSNotification` | The notification that was clicked. |
| `result.actionId` | `String` | ID of the clicked action button. `null` when the user tapped the notification body. |
| `result.url` | `String` | Launch URL of the notification, if one was set. |

<Note>
  SDK 3.x exposed click data as `OSNotificationAction` with a `type` enum (`Opened` or `ActionTaken`). That enum is not available in SDK 5.x. Check `result.actionId` instead: it is `null` for a body tap and set to the button ID when an action button was clicked.
</Note>

***

## Custom OneSignal payload structure

All OneSignal notifications include a special `"custom"` object in the payload:

```json theme={null}
{
  "custom": {
    "i": "the-notification-id"
  }
}
```

<Info>
  This key is required for OneSignal SDKs to process the notification. If missing, notifications will not trigger click events or analytics. If you send pushes from another service to devices that also use OneSignal, filter by this key to prevent duplicate processing. See [Push payload handling](./migrating-to-onesignal#push-payload-handling) for guidance.
</Info>

***

## Move additionalData to APNs root

For iOS apps, you can place `additionalData` fields in the root of the APNs payload instead of inside the `custom` dictionary. This simplifies access in custom notification handlers.

**1. Enable via the API**

Use the [Update an app API](/reference/update-an-app) and set:

```json theme={null}
{
  "additional_data_is_root_payload": true
}
```

**2. Send a push with `data`**

The `data` fields appear in the APNs root payload:

```json theme={null}
{
  "aps": {
    "alert": { "title": "Sale", "body": "20% off all items!" }
  },
  "promo_code": "SPRING20"
}
```

You can now access `promo_code` directly without checking the `custom` dictionary.

***

## Restored notifications (Android)

The Android SDK automatically redisplays (restores) notifications that Android removed from the notification shade without the user dismissing or clicking them. Restore runs when the device reboots, when the app is updated, and when the app cold starts, such as after a force-quit.

A notification is only restored when all of the following are true:

* The user did not dismiss or click it.
* It is within its TTL (time-to-live), which defaults to 3 days. Notifications older than 7 days are never restored, even with a longer TTL.
* It is not still visible in the notification shade.

The SDK restores up to 49 notifications. Restored notifications use the low-importance [Restored category](./android-notification-categories#restored), so they reappear silently without sounds or pop-ups.

There is no `OSNotification` property or API parameter to detect or disable restore. SDK version 3.x exposed a `restoring` flag on the notification payload. That flag was removed in SDK 4.0 and is not available in SDK 4.x or 5.x.

### Prevent or clear restored notifications

* **Set a shorter `ttl` when sending.** Notifications past their TTL are never restored. Use a short or `0` TTL for time-sensitive messages that should not reappear.
* **Clear notifications on app launch.** Call [`clearAllNotifications()`](./mobile-sdk-reference#clearallnotifications) when your app starts to remove all OneSignal notifications from the shade. Cleared notifications are marked as dismissed and are not restored again. To clear specific notifications, use [`removeNotification()` or `removeGroupedNotifications()`](./mobile-sdk-reference#removenotification-removegroupednotifications-android).

<Warning>
  Always clear notifications with OneSignal SDK methods. Notifications canceled with Android's native `NotificationManager.cancel()` or `cancelAll()` are not marked as dismissed, so the SDK restores them the next time the app restarts.
</Warning>

***

## Push token formats

* **iOS Push (APNs)**: 64 characters, hexadecimal only (0-9, a-f). `deviceToken.map {String(format: "%02x", $0)}.joined()`
* **Android Push (FCM)**: Typically 163 characters, alphanumeric, may contain hyphens, colons, and underscores.

***

## FAQ

### What is the maximum payload size?

The total payload is limited to 4096 bytes, and `additionalData` within it to 2048 bytes. Keep the total under 3500 bytes to avoid truncation.

### How do I identify a OneSignal notification in the raw payload?

All OneSignal notifications include a `"custom"` object with an `"i"` key containing the notification ID. Check for this key to distinguish OneSignal notifications from those sent by other providers.

### Why do old notifications reappear when the app opens on Android?

The Android SDK restores notifications that were force-removed from the notification shade, such as after a device reboot, app update, or force-quit. Notifications the user dismissed or clicked are not restored. To prevent this, set a shorter TTL when sending or call `clearAllNotifications()` on app launch. See [Restored notifications (Android)](#restored-notifications-android).

### Can I access additionalData in the APNs root payload?

Yes. Enable `additional_data_is_root_payload` via the [Update an app API](/reference/update-an-app) to place `additionalData` fields in the APNs root instead of inside the `custom` dictionary. See [Move additionalData to APNs root](#move-additionaldata-to-apns-root) for details.

***

## Related pages

<Columns cols={2}>
  <Card title="Android notification categories" icon="android" href="./android-notification-categories">
    Configure notification channels for Android 8.0+ devices.
  </Card>

  <Card title="Mobile Service Extensions" icon="puzzle-piece" href="./service-extensions">
    Add rich media, badges, and confirmed receipt tracking.
  </Card>

  <Card title="Mobile SDK reference" icon="book" href="./mobile-sdk-reference">
    Full reference for OneSignal's mobile SDK methods and listeners.
  </Card>

  <Card title="Deep linking" icon="link" href="./deep-linking">
    Route users to specific screens using launch URLs and custom data.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.