# Push Notifications

Push notifications can be configured to receive updates when the application is closed or in the background. Stream Chat sends push notification to channel members that are not online and have at least one registered device.

<admonition type="note">

You can find more on setting up push [here](/chat/docs/android/push_introduction/). Make sure you've taken care of authentication before proceeding to the next steps.

</admonition>

## Supported Providers

We support the following providers:

- [Firebase Cloud Messaging](/chat/docs/sdk/android/v6/client/guides/push-notifications/push-providers/firebase/)
- [Huawei Push Kit](/chat/docs/sdk/android/v6/client/guides/push-notifications/push-providers/huawei/)
- [Xiaomi Mi Push](/chat/docs/sdk/android/v6/client/guides/push-notifications/push-providers/xiaomi/)

We ship an individual artifact for each of these to make client-side integration with their service quick and simple. See their individual documentation pages linked above for details.

## Basic Setup

To enable push notifications, you need to configure the `NotificationConfig` with the required `PushDeviceGenerator` for your chosen provider. The `PushDeviceGenerator` is essential for registering your device with the push notification service.

**Required configuration:**

- `pushNotificationsEnabled`: Set to `true` to enable push notifications
- `pushDeviceGenerators`: List of generators for your chosen push notification provider

<tabs>

<tabs-item value="kotlin" label="Kotlin">

```kotlin
val notificationConfig = NotificationConfig(
    pushNotificationsEnabled = true, // Enable push notifications
    pushDeviceGenerators = listOf(
        // Add your desired push device generators here
        // You can include multiple generators based on your needs
        FirebasePushDeviceGenerator(),
    ),
)

ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build()
```

</tabs-item>

<tabs-item value="java" label="Java">

```java
boolean pushNotificationEnabled = true;
List<PushDeviceGenerator> pushDeviceGeneratorList = new ArrayList<>();
NotificationConfig notificationConfig = new NotificationConfig(pushNotificationEnabled, pushDeviceGeneratorList);

new ChatClient.Builder("api-key", context)
        .notifications(notificationConfig, notificationHandler)
        .build();
```

</tabs-item>

</tabs>

<admonition type="note">

Push notifications are disabled by default on the client side. You can enable it by setting the `NotificationConfig::pushNotificationsEnabled` property to `true`.
Keep in mind that the SDK creates a `NotificationChannel` during its initialization if push notifications are enabled client-side.

</admonition>

## Leveraging Multi-Bundle Configuration

If you want to support different push configurations for different build variants of your app (for example `release`, `debug`), you can leverage the multi-bundle support.

You need to register your push configuration on the [Stream Dashboard](https://dashboard.getstream.io/) following the [Multi-bundle guide](/chat/docs/android/push_providers_and_multi_bundle/).

Then, when a new device is registered, you need to add the desired `providerName`.

<tabs>

<tabs-item value="kotlin" label="Kotlin">

```kotlin
Device(
    token = "token-generated-by-provider",
    pushProvider = yourPushProvider,
    providerName = "providerName",
)
```

</tabs-item>

<tabs-item value="java" label="Java">

```java
new Device(
        "token-generated-by-provider",
        PushProvider.FIREBASE, // your push provider
        "providerName"
);
```

</tabs-item>

</tabs>

If you are using any of the artifacts integration we support, you can set them by adding an extra attribute on the constructor of the `PushDeviceGenerator` class implementation.

## Customizing Push Notifications

You can also customize how push notifications work.

You can customize push notifications in the following ways:

- Overriding resources: Simple customization of the notification's icon and text resources
- `NotificationHandlerFactory`: Uses default styling, but provides high-level customization options
- Custom `NotificationHandler`: Allows you to fully customize how notifications are shown and dismissed
- `NotificationConfig`: General, non-UI related configuration

### Overriding resources

You can provide custom icon and text resources displayed in notifications by overriding them:

- We are using [stream_ic_notification.xml](https://github.com/GetStream/stream-chat-android/blob/main/stream-chat-android-client/src/main/res/drawable/stream_ic_notification.xml) drawable as the default notification's icon
- Text resources are placed inside [strings.xml](https://github.com/GetStream/stream-chat-android/blob/main/stream-chat-android-client/src/main/res/values/strings.xml) file

<admonition type="info">

The SDK supports multiple languages. Make sure to override resources in all languages used in your app. Refer to [Adding Localization](/chat/docs/sdk/android/v6/ui/guides/custom-translations/) guide for more details.

</admonition>

### Using `NotificationHandlerFactory`

The `NotificationHandlerFactory` provides a way to create a default implementation of
`NotificationHandler` based on the Android API Level and lets you customize various top-level
aspects of push notifications without the need to implement the entire `NotificationHandler`
interface.

#### Customizing the notification click intent

You can customize the intent that is triggered when a user clicks on a notification by providing a
lambda function to the `newMessageIntent` parameter of the `createNotificationHandler` method:

<tabs>

<tabs-item value="kotlin" label="Kotlin">

```kotlin
val notificationHandler = NotificationHandlerFactory.createNotificationHandler(
    context = context,
    notificationConfig = notificationConfig,
    newMessageIntent = { message: Message, channel: Channel ->
        // Return the intent you want to be triggered when the notification is clicked
        val intent: Intent = [....]
        intent
    }
)

ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build()

```

</tabs-item>

<tabs-item value="java" label="Java">

```java
boolean pushNotificationEnabled = true;
List<PushDeviceGenerator> pushDeviceGeneratorList = new ArrayList<>();
NotificationConfig notificationConfig = new NotificationConfig(pushNotificationEnabled, pushDeviceGeneratorList);

NotificationHandler notificationHandler = NotificationHandlerFactory.createNotificationHandler(context, notificationConfig, (message, channel) -> {
    // Return the intent you want to be triggered when the notification is clicked
    Intent intent = new Intent();

    return intent;
});

new ChatClient.Builder("api-key", context)
        .notifications(notificationConfig, notificationHandler)
        .build();
```

</tabs-item>

</tabs>

#### Customizing the notification channel

The SDK creates a default `NotificationChannel` during its initialization if push notifications are
enabled client-side. You can customize this channel by providing a lambda function to the
`notificationChannel` parameter of the `createNotificationHandler` method:

```kotlin
val notificationHandler = NotificationHandlerFactory.createNotificationHandler(
    // Other setup...
    notificationChannel = {
        NotificationChannel("channel-id", "Chat Messages", NotificationManager.IMPORTANCE_DEFAULT)
    },
)
```

#### Customizing the sender icon

You can customize how the sender icon is displayed in the notification by providing a custom
`UserIconBuilder` implementation to the `userIconBuilder` parameter of the
`createNotificationHandler` method:

```kotlin
val notificationHandler = NotificationHandlerFactory.createNotificationHandler(
    // Other setup...
    userIconBuilder = object : UserIconBuilder {
        override suspend fun buildIcon(user: User): IconCompat? {
            // Your implementation to build an IconCompat from the User object
        }
    },
)
```

#### Customizing the notification text

You can customize the text displayed in the notification by providing a custom lambda for the
`notificationTextFormatter` parameter of the `createNotificationHandler` method:

```kotlin
val notificationHandler = NotificationHandlerFactory.createNotificationHandler(
    // Other setup
    notificationTextFormatter = { currentUser: User?, message: Message ->
        // Your implementation to format the notification text, ex:
        "${message.user.name}: ${message.text}"
    },
)
```

<admonition type="info">
The <b>notificationTextFormatter</b> is applied only for notifications of type: TYPE_MESSAGE_NEW, TYPE_MESSAGE_UPDATED and TYPE_NOTIFICATION_REMINDER_DUE.
</admonition>

#### Customizing the notification actions

By default, the notifications include action buttons for replying to the message and marking it as
read. You can customize these actions by providing a custom lambda for the `actionsProvider`
parameter of the `createNotificationHandler` method:

```kotlin
val notificationHandler = NotificationHandlerFactory.createNotificationHandler(
    // Other setup
    actionsProvider = { notificationId: Int, channel: Channel, message: Message ->
        // Your implementation to provide actions for the notification
    },
)
```

To retrieve/customize the default actions, you can use the `NotificationActionsFactory` class. It
provides two methods:

- `createReplyAction`: Creates a reply action for the notification
- `createMarkReadAction`: Creates a mark as read action for the notification

```kotlin
val notificationHandler = NotificationHandlerFactory.createNotificationHandler(
    // Other setup
    actionsProvider = { notificationId: Int, channel: Channel, message: Message ->
        val customReply = NotificationActionsFactory.createReplyAction(
            context = context,
            notificationId = notificationId,
            channel = channel,
            // Custom title and input hint
            title = "Reply now",
            hint = "Write a message to ${channel.name}",
        )
        val customMarkRead = NotificationActionsFactory.createMarkReadAction(
            context = context,
            notificationId = notificationId,
            channel = channel,
            message = message,
            // Custom title
            title = "Already seen",
        )
        listOf(customMarkRead, customReply)
    },
)
```

<admonition type="info">
The actions are shown only for notifications of type TYPE_MESSAGE_NEW and TYPE_MESSAGE_UPDATED.
</admonition>

#### Transforming the notification before showing it

Instead of fully customizing the notification display logic, you can transform the notification
after it was created by the SDK, but before it is shown to the user. You can do this by providing
a custom lambda for the `notificationBuilderTransformer` parameter of the
`createNotificationHandler`:

```kotlin
val notificationHandler = NotificationHandlerFactory.createNotificationHandler(
    // Other setup
    notificationBuilderTransformer = { builder: NotificationCompat.Builder, notification: ChatNotification ->
        // Your implementation to transform the notification builder
        builder
    },
)
```

<admonition type="info">
The SDK sets the notification style using the
<b>NotificationCompat.Builder.setStyle(MessagingStyle)</b> method.
If you want to update the content title or text of the notification by calling
<b>builder.setContentTitle(title)</b> or <b>builder.setContentText(text)</b>, make sure to remove
the style first by calling <b>builder.setStyle(null)</b>.
Otherwise, the content title/text might not be updated as expected.
</admonition>

#### Controlling whether the push message should be shown or not

You can control whether push notifications should be processed when received. You can define this
behavior by providing a custom lambda for the `onPushMessage` parameter of the
`createNotificationHandler` method. You can also use this callback to perform any side effects
when a push message is received. By default, the SDK handles all push messages internally.

```kotlin
val notificationHandler = NotificationHandlerFactory.createNotificationHandler(
    // Other setup
    onPushMessage = { message: PushMessage ->
        // Your implementation to determine whether to show the notification
        // Return true to handle the message yourself, false to let the SDK handle it internally
        true // or false
    },
)
```

### Custom `NotificationHandler`

The SDK allows you to fully override how the incoming push notifications are handled.
To do this, implement the `NotificationHandler` interface and show your own notification.
If you want to dismiss notifications when a user visits a channel or logs off of the app,
you will need to implement methods for dismissing notifications on the `NotificationHandler` class.

The `NotificationHandler` interface provides several methods to handle different types of events:

- **`onChatEvent(event: NewMessageEvent)`**: Handles WebSocket events for new messages when the user is connected. This method is only invoked when the user has an active WebSocket connection. You can use this to control whether to show notifications while the user is active in the app. Return `true` to handle the event yourself, `false` to let the SDK handle it internally.
- **`onNotificationReminderDueEvent(event: NotificationReminderDueEvent)`**: Handles WebSocket events for reminder notifications when the user is connected. This method is only invoked when the user has an active WebSocket connection. Return `true` to handle the event yourself, `false` to let the SDK handle it internally.
- **`onPushMessage(message: PushMessage)`**: Acts as a bypass to control whether push notifications should be processed when received. Return `true` to handle the push message yourself, `false` to let the SDK handle it internally.
- **`showNotification(notification: ChatNotification)`**: Shows notifications for different types of notifications. Supported types are: `MessageNew`, `MessageUpdated`, `ReactionNew` and `NotificationReminderDue`.
- **`dismissChannelNotifications(channelType: String, channelId: String)`**: Dismisses all notifications for a specific channel.
- **`dismissAllNotifications()`**: Dismisses all notifications.
- **`onNotificationPermissionStatus(status: NotificationPermissionStatus)`**: Handles notification permission lifecycle.

<tabs>

<tabs-item value="kotlin" label="Kotlin">

```kotlin
class MyNotificationHandler(private val context: Context) : NotificationHandler {
    private val notificationManager: NotificationManager by lazy {
        context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    }

    override fun onNotificationPermissionStatus(status: NotificationPermissionStatus) {
        when (status) {
            NotificationPermissionStatus.REQUESTED -> {
                // invoked when POST_NOTIFICATIONS permission is requested
            }
            NotificationPermissionStatus.GRANTED -> {
                // invoked when POST_NOTIFICATIONS permission is granted
            }
            NotificationPermissionStatus.DENIED -> {
                // invoked when POST_NOTIFICATIONS permission is denied
            }
            NotificationPermissionStatus.RATIONALE_NEEDED -> {
                // invoked when POST_NOTIFICATIONS permission requires rationale
            }
        }
    }

    override fun showNotification(notification: ChatNotification) {
        when (notification) {
            is ChatNotification.MessageNew -> {
                // Handle new message notification
                // You can customize the notification here
            }
            is ChatNotification.ReactionNew -> {
                // Handle new reaction notification
                // You can customize the notification here
            }
            is ChatNotification.MessageUpdated -> {
                // Handle message updated notification
                // You can customize the notification here
            }
            is ChatNotification.NotificationReminderDue -> {
                // Handle reminder notification
                // You can customize the notification here
            }
        }
    }

    override fun dismissChannelNotifications(channelType: String, channelId: String) {
        // Dismiss all notification related with this channel
    }

    override fun dismissAllNotifications() {
        // Dismiss all notifications
    }
}
```

</tabs-item>

<tabs-item value="java" label="Java">

```java
class MyNotificationHandler implements NotificationHandler {

    NotificationManager notificationManager;

    public MyNotificationHandler(Context context) {
        notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE) ;
    }

    @Override
    public void onNotificationPermissionStatus(@NonNull NotificationPermissionStatus status) {
        switch (status) {
            case REQUESTED:
                // invoked when POST_NOTIFICATIONS permission is requested
                break;
            case GRANTED:
                // invoked when POST_NOTIFICATIONS permission is granted
                break;
            case DENIED:
                // invoked when POST_NOTIFICATIONS permission is denied
                break;
            case RATIONALE_NEEDED:
                // invoked when POST_NOTIFICATIONS permission requires rationale
                break;
        }
    }

    @Override
    public void showNotification(@NonNull ChatNotification notification) {
        if (notification instanceof ChatNotification.MessageNew) {
            ChatNotification.MessageNew messageNew = (ChatNotification.MessageNew) notification;
            // Handle new message notification
            // You can customize the notification here
        } else if (notification instanceof ChatNotification.ReactionNew) {
            ChatNotification.ReactionNew reactionNew = (ChatNotification.ReactionNew) notification;
            // Handle new reaction notification
            // You can customize the notification here
        } else if (notification instanceof ChatNotification.MessageUpdated) {
            ChatNotification.MessageUpdated messageUpdated = (ChatNotification.MessageUpdated) notification;
            // Handle message updated notification
            // You can customize the notification here
        } else if (notification instanceof ChatNotification.NotificationReminderDue) {
            ChatNotification.NotificationReminderDue reminderDue = (ChatNotification.NotificationReminderDue) notification;
            // Handle reminder notification
            // You can customize the notification here
        }
    }

    @Override
    public void dismissChannelNotifications(@NonNull String channelType, @NonNull String channelId) {
        // Dismiss all notification related with this channel
    }

    @Override
    public void dismissAllNotifications() {
        // Dismiss all notifications
    }
}
```

</tabs-item>

</tabs>

Finally, pass the `NotificationHandler` implementation to the `ChatClient.Builder` when initializing the Stream Android SDK:

<tabs>

<tabs-item value="kotlin" label="Kotlin">

```kotlin {4}
val notificationHandler = MyNotificationHandler(context)

ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build()
```

</tabs-item>

<tabs-item value="java" label="Java">

```java {4}
NotificationHandler notificationHandler = new MyNotificationHandler(context);

new ChatClient.Builder("api-key", context)
        .notifications(notificationConfig, notificationHandler)
        .build();
```

</tabs-item>

</tabs>

### Using `NotificationConfig`

The `NotificationConfig` class provides comprehensive control over push notification behavior.
Here's a detailed explanation of each property:

#### WebSocket Connection Behavior

**`ignorePushMessageWhenUserOnline: (type: String) -> Boolean`**
Controls whether push notifications should be shown when the user has an active WebSocket connection. This allows you to customize behavior based on notification type.

**Supported notification types:**

- `ChatNotification.TYPE_MESSAGE_NEW` - New message notifications
- `ChatNotification.TYPE_MESSAGE_UPDATED` - Message updated notifications
- `ChatNotification.TYPE_REACTION_NEW` - New message reaction notifications
- `ChatNotification.TYPE_NOTIFICATION_REMINDER_DUE` - Reminder notifications

**Default behavior:**

- New message, message updated and reaction notifications are ignored when the user has an active WebSocket connection
- Reminder notifications are always shown, even when the user has an active WebSocket connection

```kotlin
val notificationConfig = NotificationConfig(
    ignorePushMessageWhenUserOnline = { type ->
        when (type) {
            ChatNotification.TYPE_MESSAGE_NEW -> true // Ignore new messages when online
            ChatNotification.TYPE_MESSAGE_UPDATED -> true // Ignore message updates when online
            ChatNotification.TYPE_REACTION_NEW -> true // Ignore reactions when online
            ChatNotification.TYPE_NOTIFICATION_REMINDER_DUE -> false // Always show reminders
            else -> true // Default behavior for unknown types
        }
    }
)
```

#### Runtime Notification Control

**`shouldShowNotificationOnPush: () -> Boolean = { true }`**
Allows you to control whether notifications should be displayed after receiving a push message. This function is called for each push notification received and can be changed at runtime.

This is particularly useful when users want to temporarily disable notifications or when you need to implement custom logic based on your app's internal state.

```kotlin
val notificationConfig = NotificationConfig(
    shouldShowNotificationOnPush = {
        // Custom logic to determine if notification should be shown
        // For example, only show notifications during certain hours
        val currentHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
        currentHour in 8..22 // Only show notifications between 8 AM and 10 PM
    }
)
```

#### Permission Management

**`requestPermissionOnAppLaunch: () -> Boolean = { true }`**
Controls whether the SDK should automatically request the `POST_NOTIFICATIONS` permission when the app launches. This is particularly important for Android 13+ where notification permission is required.

<admonition type="warning">
If you set this to <b>false</b>, you must handle the <b>POST_NOTIFICATIONS</b> permission request yourself. Otherwise, push notifications may not work properly on Android 13+ devices.
</admonition>

```kotlin
val notificationConfig = NotificationConfig(
    requestPermissionOnAppLaunch = {
        // Custom logic to determine if permission should be requested
        // For example, only request on first app launch
        isFirstAppLaunch()
    }
)
```

#### Advanced Features

**`autoTranslationEnabled: Boolean = false`**
Enables or disables the auto-translation feature for push notifications. When enabled, notifications will be automatically translated based on the user's language preferences.

```kotlin
val notificationConfig = NotificationConfig(
    autoTranslationEnabled = true // Enable automatic translation
)
```

#### Complete Configuration Example

Here's a complete example showing how to configure all properties:

<tabs>

<tabs-item value="kotlin" label="Kotlin">

```kotlin
val notificationConfig = NotificationConfig(
    // WebSocket connection behavior
    ignorePushMessageWhenUserOnline = { type ->
        when (type) {
            ChatNotification.TYPE_MESSAGE_NEW -> true
            ChatNotification.TYPE_NOTIFICATION_REMINDER_DUE -> false
            else -> true
        }
    },

    // Runtime notification control
    shouldShowNotificationOnPush = {
        val currentHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
        currentHour in 8..22
    },

    // Permission management
    requestPermissionOnAppLaunch = { true },

    // Advanced features
    autoTranslationEnabled = true,
)

ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build()
```

</tabs-item>

<tabs-item value="java" label="Java">

```java
NotificationConfig notificationConfig = new NotificationConfig(
    type -> { // ignorePushMessageWhenUserOnline
        switch (type) {
            case ChatNotification.TYPE_MESSAGE_NEW:
                return true;
            case ChatNotification.TYPE_NOTIFICATION_REMINDER_DUE:
                return false;
            default:
                return true;
        }
    },
    () -> { // shouldShowNotificationOnPush
        Calendar calendar = Calendar.getInstance();
        int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
        return currentHour >= 8 && currentHour <= 22;
    },
    () -> true, // requestPermissionOnAppLaunch
    false, // autoTranslationEnabled
);

new ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build();
```

</tabs-item>

</tabs>

## Dismissing Notifications

Our [`MessageListView`](/chat/docs/sdk/android/v6/ui/message-components/message-list/) UI component and [`MessageList`](/chat/docs/sdk/android/v6/compose/message-components/message-list/) Compose UI Component automatically dismiss notifications related to a `Channel` when the user opens it.

If you need to dismiss them manually (for example, if you are using a custom `MessageListView` component) you can call the `ChatClient::dismissChannelNotifications` method, providing the `channelType` and `channelId` from the `Channel` that you would like to dismiss notifications:

<tabs>

<tabs-item value="kotlin" label="Kotlin">

```kotlin
ChatClient.instance().dismissChannelNotifications("messaging", "general")
```

</tabs-item>

<tabs-item value="java" label="Java">

```java
ChatClient.instance().dismissChannelNotifications("messaging", "general");
```

</tabs-item>

</tabs>

Notifications are also automatically dismissed when the user logs out from the SDK.

## Handling Expired JWT Tokens

A common scenario with short-lived Stream JWT tokens is receiving a push
notification while the app is killed, and the Stream JWT token is already expired. In this case,
the SDK cannot properly invoke the `TokenProvider` that you would pass via the
`ChatClient::connectUser` method, because in a common use case, you would not automatically connect
the user when receiving a push notification, thus the `ChatClient` will not have a registered
`TokenProvider` (yet). The SDK however, must internally fetch some data from
the Stream server to properly show the notification, and for this it needs a valid JWT token.
To bypass this, the `NotificationConfig` class provides a `tokenProvider` property, that you can set
at the time of building the `ChatClient`, without the need to call `connectUser`. This
`TokenProvider` will be invoked **only** in this specific scenario, when the `ChatClient` attempts
to load notification data with an expired JWT token, and the app still hasn't called `connectUser`.

You can set this `TokenProvider` as follows:

```kotlin
val notificationConfig = NotificationConfig(
    tokenProvider = CustomTokenProvider(),
)
ChatClient.Builder("api-key", context)
    .notifications(notificationConfig, notificationHandler)
    .build()
```

<admonition type="warning">
This <b>TokenProvider</b> is only used to retrieve a valid Stream JWT token when showing a push
notification before the app has called <b>ChatClient::connectUser</b>. You still need to pass a valid
<b>TokenProvider</b> when connecting the user via <b>ChatClient::connectUser</b>.
</admonition>

## Unsubscribing from Push Notifications

If you want to permanently stop receiving push notifications on a device, you need to delete the
device from the Stream backend. There are two ways to do this:

- Automatic deletion: The deletion of the device can be done automatically when the user disconnects
  from the SDK. This is controlled by the `deleteDevice` parameter of the `disconnect` method:

```kotlin
// Setting deleteDevice to true will result in the
// device being deleted from Stream backend
ChatClient.instance()
    .disconnect(flushPersistence = true, deleteDevice = true)
    .enqueue()
```

<admonition type="info">
The <b>deleteDevice</b> flag is available since
<b><a href="https://github.com/GetStream/stream-chat-android/releases/tag/6.26.0">6.26.0</a></b>
of the SDK. In older versions of the SDK,
the automatic deletion is controlled by the <b>flushPersistence</b> flag of the <b>disconnect</b>
method. To delete the registered device from the Stream backend, you need to call:
<b>ChatClient.instance().disconnect(flushPersistence = true).enqueue()</b>
</admonition>

- Manual deletion: If you want to fully control when the device is deleted, you can manually delete
  the device by calling `ChatClient::deleteDevice`, providing the device ID (push token) you used when
  registering the device:

```kotlin
val device = Device(
    token = "your_push_token", // ex. Firebase/Huawei/Xiaomi token
    pushProvider = PushProvider.FIREBASE, // or HUAWEI, XIAOMI
    providerName = "your_push_provider_name",
)
ChatClient.instance()
    .deleteDevice(device)
    .enqueue()
```

## Troubleshooting Push Notifications

<admonition type="note">

Push notifications can be tricky to setup correctly.

Here's few articles that might help to troubleshoot your issues:

- [Testing Push Notifications](/chat/docs/android/push_test/)
- [Set up logging on Stream Dashboard](/chat/docs/android/push_-_common_issues_and_faq/)
- [Check for errors and settings on the Dashboard](https://getstream.io/dashboard/) and refer to our debugging tips for [common error scenarios](/chat/docs/android/push_-_common_issues_and_faq/).

</admonition>


---

This page was last updated at 2026-04-17T17:33:31.123Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/android/v6/client/guides/push-notifications/](https://getstream.io/chat/docs/sdk/android/v6/client/guides/push-notifications/).