---
source_url: https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/configuration
title: Initial configuration
updated_at: 2026-06-15T12:11:30.005Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Initial configuration

Initialize and configure the Chat SDK before building your chat app.

## Prerequisites

1. [Sign in](https://admin.pubnub.com/#/login) or [create an account](https://admin.pubnub.com/#/register) on the Admin Portal.
2. [Create an app](https://www.youtube.com/watch?v=ou5RMN1LQ1Y&t=19s&ab_channel=PubNub) to get your **Publish Key** and **Subscribe Key**.

:::warning Limit of 3 keysets for Free tier accounts
Effective February 3, 2025, all [Free tier](https://www.pubnub.com/pricing/) accounts are limited to a maximum of three keysets. If your account exceeds this limit, you must delete existing keysets to create new ones.
:::

A new app receives demo keys automatically. You can create multiple keysets per app. Use separate keysets for production and test environments.

:::warning Required keyset settings
Enable these features on your keyset in the Admin Portal:
* **App Context** - Store user and channel data
* **Presence** - Track online/offline status
* **Message Persistence** - Store message history
:::

## Download the SDK

Download the SDK from any of the following sources:

### Use Maven

To integrate PubNub into your project using Maven, add the following dependency in your `pom.xml`:

```xml
<dependency>
   <groupId>com.pubnub</groupId>
   <artifactId>pubnub-chat</artifactId>
   <version>1.0.0</version>
</dependency>
```

### Use Gradle

To integrate PubNub into your project using Gradle (including Android Studio), add the following dependency in your `build.gradle` file:

```bash
implementation ("com.pubnub:pubnub-chat:1.0.0")
```

:::note Android ProGuard/R8 configuration
If you're building for Android, make sure your ProGuard/R8 configuration includes the required rules for the Kotlin SDK. This includes a rule to prevent `org.json` from being obfuscated, which can cause startup crashes. Refer to the [Kotlin SDK setup guide](https://www.pubnub.com/docs/sdks/kotlin#configure-proguard) for the full ProGuard configuration.
:::

### Get the source code

[https://github.com/pubnub/kmp-chat](https://github.com/pubnub/kmp-chat)

## Initialize PubNub

Use the `init()` method to create a Chat SDK instance. Two parameters are required: `subscribeKey` and `userId`.

Optional parameters configure features like typing indicators, presence tracking, push notifications, and rate limiting.

:::note Extended configuration
The Chat SDK supports all [Kotlin SDK configuration options](https://www.pubnub.com/docs/sdks/kotlin/api-reference/configuration#configuration). For example, use `authToken` with [Access Manager](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/permissions) for production apps. See [Additional configuration options](#additional-configuration-options) for details.
:::

### Method signature

```kotlin
Chat.init(chatConfig: ChatConfiguration, pnConfiguration: PNConfiguration)

// Chat SDK-specific configuration
interface ChatConfiguration {
    val logLevel: LogLevel
    val typingTimeout: Duration
    val storeUserActivityInterval: Duration
    val storeUserActivityTimestamps: Boolean
    val pushNotifications: PushNotificationsConfig {
      val sendPushes: Boolean,
      val deviceToken: String?,
      val deviceGateway: PNPushType,
      val apnsTopic: String?,
      val apnsEnvironment: PNPushEnvironment
    }
    val rateLimitFactor: Int
    val rateLimitPerChannel: Map<ChannelType, Duration>
    val customPayloads: CustomPayloads?
    val emitReadReceiptEvents: Map<ChannelType, Boolean>
    val syncMutedUsers: Boolean
}

// PNConfiguration instance is storage for user-provided information which describes further PubNub client behavior. The configuration instance contains additional set of properties which allow performing precise PubNub client configuration.
val pnConfiguration = PNConfiguration.builder(
    userId: String,
    subscribeKey: String,
    ) {
      publishKey: String?
      authToken: String?
      // Other, optional, configuration parameters from this list: https://www.pubnub.com/docs/sdks/kotlin/api-reference/configuration#configuration
    }
```

### Input parameters

| Parameter | Feature | Description |
| --- | --- | --- |
| logLevel | LogLevel | Optional | `WARN` | [Error logging](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/error-logging) | Specifies if any Chat SDK-related errors should be logged. It's disabled by default. Available options include: `OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, and `VERBOSE`. |
| typingTimeout | Duration | Optional | `5.seconds` | [Typing Indicator](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/typing-indicator) | Specifies the default timeout after which the [typing indicator](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/typing-indicator) automatically stops when no typing signals are received. The default value is set to 5 seconds. Minimal to 1 seconds. |
| storeUserActivityInterval | Duration | Optional | `600.seconds` | [User's last online activity, global presence](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/presence#global-presence) | Specifies how often the user global presence in the app should be updated. Requires `storeUserActivityTimestamps` to be set to `true`. The default value is set to 600 seconds (10 minutes). The minimum possible value is 60 seconds. If you try to set it to a lower value, you'll get the `storeUserActivityInterval must be at least 60000ms` error. |
| storeUserActivityTimestamps | Boolean | Optional | `false` | [User's last online activity, global presence](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/presence#global-presence) | Specifies if you want to track the user's [global presence](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/presence#global-presence) in your chat app. The user's activity is tracked through the [lastActiveTimestamp](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/user) parameter on the `User` object. |
| pushNotifications | PushNotificationsConfig | Optional |  | [Push Notifications](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/push-notifications) | List of parameters you must set if you want to enable sending/receiving [mobile push notifications](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/push-notifications) for phone devices, either through Apple Push Notification service (APNS) or Firebase Cloud Messaging (FCM). |
| → sendPushes | Boolean | Optional | `false` | as above | The main option for enabling sending notifications. It must be set to `true` if you want a particular client (whether a mobile device, web browser, or server) to send push notifications to mobile devices. These push notifications are messages with a provider-specific payload that the Chat SDK automatically attaches to every message. Chat SDK includes a [default payload setup](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/push-notifications) for `deviceGateway` in every message sent to the registered channels. This is the only required option to enable if you want to send push notifications to Android devices. For iOS devices, you also have to configure `apnsTopic`. |
| → deviceToken | String | Optional |  | as above | Option for receiving notifications on iOS and Android devices. A device token refers to the unique identifier assigned to a specific mobile device by a platform's push notification service. It targets and delivers push notifications to the intended app on that specific device. Suppose you don't set this option and try to run [channel registration-related methods](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/push-notifications#register-selected-push-channels). In that case, you'll get the `Device Token has to be defined in Chat pushNotifications config` error. Refer to the official [Apple](https://developer.apple.com/documentation/usernotifications/registering_your_app_with_apns#2942135) and [Google](https://firebase.google.com/docs/cloud-messaging/ios/client) docs to learn how to obtain a device token for the APNs and FCM services. |
| → deviceGateway | PNPushType | Optional | `FCM` | as above | Option for receiving push notifications on Android (`fcm`) or iOS (`apns` or `apns2`) devices. These are the available types: APNS - Apple Push Notification service (legacy), APNS2 - Apple Push Notification service (new), FCM - Firebase Cloud Messaging (new) |
| → apnsTopic | String | Optional |  | as above | An Apple specific-option for sending and receiving notifications. This string is a [bundle ID](https://help.apple.com/xcode/mac/current/#/deve70ea917b) that you must define yourself for your iOS app so that Apple could [enable push notifications](https://help.apple.com/xcode/mac/current/#/devdfd3d04a1) for it in APNs. The string takes the following format: `com.domainname.applicationname`. Apple combines that ID with your Team ID (generated by Apple) and creates an [App ID](https://help.apple.com/xcode/mac/current/#/dev618af4e67) for your application. To send pushes from an iOS device, you must also set `sendPushes` to `true`. To receive pushes on an iOS device, you must also set `deviceGateway` to `apns2`, define `deviceToken`, and `apnsEnvironment`. Suppose you don't configure `apnsTopic`, but set `deviceGateway` to `apns2`. In that case, you'll get the `apnsTopic has to be defined when deviceGateway is set to apns2` error and Chat SDK won't attach the `apns` payload to messages. |
| → apnsEnvironment | PNPushEnvironment | Optional | `DEVELOPMENT` | as above | Option for receiving notifications on iOS devices. When registering for push notifications, this option specifies whether to use the development (`DEVELOPMENT`) or production (`PRODUCTION`) [APNs environment](https://developer.apple.com/documentation/bundleresources/entitlements/aps-environment). |
| rateLimitFactor | Int | Optional | `2` | [Client-side rate limiting](#client-side-rate-limiting) | The so-called ["exponential backoff"](https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/) which multiplicatively decreases the rate at which messages are published on channels. It's bound to the `rateLimitPerChannel` parameter and is meant to prevent message spamming caused by excessive retries. The default value of `2` means that if you set `rateLimitPerChannel` for direct channels to 1 second and try to send three messages on such a channel type within the span of one second, the second message will be published one second after the first one (just like the `rateLimitPerChannel` value states), but the third one will be published two seconds after the second one, meaning the publishing time is multiplied by `2`. |
| rateLimitPerChannel | Map<ChannelType, | Optional |  | [Client-side rate limiting](#client-side-rate-limiting) | Client-side limit that states the rate at which messages can be published on a given channel type. Its purpose is to prevent message spamming in your chat app. This parameter takes an object with these three parameters: `direct`, `group`, and `public`. For example, if you decide that messages on all `direct` channels must be published no more often than every second, this is how you set it: `ChatConfiguration(rateLimitPerChannel = RateLimitPerChannel(direct = 1.seconds))`. |
| → direct | Duration | Optional | `0 (no limit)` | as above | Rate set on all direct (1:1) channels at which messages can be published. |
| → group | Duration | Optional | `0 (no limit)` | as above | Rate set on all group channels at which messages can be published. |
| → public | Duration | Optional | `0 (no limit)` | as above | Rate set on all public channels at which messages can be published. |
| → unknown | Duration | Optional | `0 (no limit)` | as above | Rate set on all channels created using the [Kotlin SDK](https://www.pubnub.com/docs/sdks/kotlin/api-reference/objects#set-channel-metadata) instead of Kotlin Chat SDK. |
| customPayloads | CustomPayloads | Optional |  | [Send and receive messages](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/messages/send-receive) | Property that lets you define your custom message payload to be sent and/or received by Chat SDK on one or all channels, whenever it differs from the default `message.text` Chat SDK payload. It also lets you configure your own message actions whenever a message is edited or deleted. For examples, check [Custom payload](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/configuration#custom-payload). |
| → getMessagePublishBody | Function | Optional |  | as above | Function that lets Chat SDK send your custom payload structure. It defines the structure of your own message payload's body (of `any` type) that you're sending through PubNub. Expand the [Message-related types](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/message#properties) section for more details on the required `TextMessageContent` structure. Define `getMessageResponseBody` whenever you use `getMessagePublishBody`. |
| → getMessageResponseBody | Function | Optional |  | as above | Function that lets Chat SDK receive your custom payload structure. Use it to let Chat SDK translate your custom message payload into the default Chat SDK message format (defined in `TextMessageContent`). Expand the [Message-related types](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/message#properties) section for more details on the required `TextMessageContent` structure. Define `getMessagePublishBody` whenever you use `getMessageResponseBody`. |
| → editMessageActionName | String | Optional |  | as above | A type of action you want to be added to your [Message](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/message) object whenever a published message is edited, like `"changed"` or `"modified"`. The default message reaction used by Chat SDK is `"edited"`. Expand the [Message-related types](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/message#properties) section for more details. |
| → deleteMessageActionName | String | Optional |  | as above | A type of action you want to be added to your [Message](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/message) object whenever a published message is deleted, like `"removed"`. The default message reaction used by Chat SDK is `"deleted"`. Expand the [Message-related types](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/message#properties) section for more details. |
| → reactionsActionName | String | Optional |  | as above | A type of action you want to be added to your [Message](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/message) object whenever a reaction is added to a published message, like `"reacted"`. The default message reaction used by Chat SDK is `"reactions"`. Expand the [Message-related types](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/learn/chat-entities/message#properties) section for more details. |
| emitReadReceiptEvents | Map<ChannelType, | Optional | `See below` | [Read receipts](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/messages/read-receipts) | Specifies whether read receipt events should be emitted per channel type. Defaults to `true` for `direct`, `group`, and `unknown` channel types, and `false` for `public` channels. When set to `false` for a given channel type, the SDK will not emit read receipt events for channels of that type. |
| syncMutedUsers | Boolean | Optional | `false` | [User moderation](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/moderation-user) | Whether the mute list is synchronized across sessions and devices. For more information, refer to [Sync muted users](#sync-muted-users). |
| userId | String | Yes |  | n/a | [Unique User ID](https://www.pubnub.com/docs/general/setup/users-and-devices) that becomes your app's current user. It's a string of up to 92 characters that identifies a single client (end user, device, or server) that connects to PubNub. Based on User ID, PubNub calculates pricing for your apps' usage. User ID should be persisted and remain unchanged. If you don't set `userId`, you won't be able to connect to PubNub. |
| subscribeKey | String | Yes |  | [Receive messages](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/messages/send-receive) | Specifies the key used to subscribe to a channel. |
| publishKey | String | Optional |  | [Send messages](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/messages/send-receive) | Specifies the key used to publish messages on a channel. |

#### Sync muted users

The `syncMutedUsers` parameter determines whether the [mute list](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/moderation-user) is synchronized across sessions and devices using a specific App Context User object.

When set to `false`, the mute list modifications are stored only for the duration of the current session. Once the session ends, the mute list is cleared.

When set to `true`, the client-side mute list is automatically saved and retrieved from App Context, ensuring that the muted user list persists beyond the current session. App Context uses a designated channel where all mute list data is sent: `PN_PRIV.{userId}.mute.1`.

:::warning Mute list and Access Manager
If you use [Access Manager](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/moderation) within your chat app and `syncMutedUsers` is enabled, you must grant the Chat SDK user the following permissions:
* `read` permission to the `PN_PRIV.{userId}.mute.1` channel.
* `update`, `delete`, and `get` permissions for the `PN_PRIV.{userId}.mute.1` user.
Make sure to change `$currentUserId` to the user ID of the chat user that will use the mute list functionality.
:::

#### Additional configuration options

Since the Chat SDK heavily relies on the latest [Kotlin SDK](https://www.pubnub.com/docs/sdks/kotlin) for all the underlying methods, when initializing the Chat SDK client, you can also make use of all optional parameters that come with the Kotlin SDK.

For example, you may want to use [Access Manager](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/permissions) and initialize the Chat SDK with `secretKey` (in the server-side code) or `token` inside `PNConfiguration` that is passed to the `Chat.init()` method (in the client-side code). You can also decide how long the server will consider the client alive for presence (`presenceTimeout`) or how often the client will announce itself to the server (`heartbeatInterval`).

For the whole list of all such inherited optional parameters which you can define when initializing the Chat SDK instance, check the [Kotlin SDK configuration document](https://www.pubnub.com/docs/sdks/kotlin/api-reference/configuration#methods).

### Output parameters

| Type | Description |
| --- | --- |
| `PNFuture<Chat>` | Object returning a new PubNub chat instance. |

### Sample code

#### Required setup

Use this basic example to initialize the client with only the required parameters.

```kotlin
// initialize your Chat SDK client using your app keys from the Admin Portal and a unique user ID for your client that you'll come up with
val chatConfig = ChatConfiguration()
val pnConfiguration = PNConfiguration.builder(userId = UserId("myUserId"), subscribeKey = "mySubscribeKey").build()

Chat.init(chatConfig, pnConfiguration).async { result ->
    result.onSuccess { chat: Chat ->
        println("Chat successfully initialized")
    }.onFailure { exception: PubNubException ->
        println("Exception initialising chat: ${exception.message}")
    }
}
```

#### Initialize Chat SDK with Access Manager

Use a PubNub SDK instance [initialized with secretKey](https://www.pubnub.com/docs/general/security/access-control#server-side-operations) to [generate a token](https://www.pubnub.com/docs/chat/security) and return it to the client-side code. Then, initialize the PubNub Chat SDK and set the `authToken` to the token returned from the server-side code.

```kotlin
// initialize your Chat SDK client using your app keys from the Admin Portal and a unique user ID for your client that you'll come up with
val chatConfig = ChatConfiguration()
val userIdValue = "clientAppUserId"
val clientChat: Chat

val token = serverChat.pubNub.grantToken(
    ttl = 100,
    channels = listOf(ChannelGrant.name(get = true, name = "anyChannelForNow")),
    uuids = listOf(UUIDGrant.id(id = userIdValue, get = true, update = true))
).await().token

val pnConfiguration = PNConfiguration.builder(userId = UserId(userIdValue), subscribeKey = "mySubscribeKey").apply {
    authToken = token
}.build()

Chat.init(chatConfig, pnConfiguration).async { result ->
    result.onSuccess { chat: Chat ->
        println("Chat successfully initialized")
    }.onFailure { exception: PubNubException ->
        println("Exception initialising chat: ${exception.message}")
    }
}
```

When a token expires, or a new token is needed because of changes in permissions, you must generate a new token on the server side and set it on the client side.

```kotlin
clientChat.pubNub.setToken(newToken)
```

#### Typing indicator timeout

Initialize the PubNub Chat SDK and set the default typing indicator timeout value to three seconds.

```kotlin
val chatConfig = ChatConfiguration(typingTimeout = 3.seconds)
val pnConfiguration = PNConfiguration.builder(userId = UserId("myUserId"), subscribeKey = "mySubscribeKey").build()

Chat.init(chatConfig, pnConfiguration).async { result ->
    result.onSuccess { chat: Chat ->
        println("Chat successfully initialized")
    }.onFailure { exception: PubNubException ->
        println("Exception initialising chat: ${exception.message}")
    }
}
```

#### Client-side rate limiting

Initialize the PubNub Chat SDK and set the hard limit for message publishing on public channels to three seconds. If there are more publish retries within this limit, multiply each retry limit by `3`.

```kotlin
val chatConfig = ChatConfiguration(rateLimitFactor = 3, rateLimitPerChannel = RateLimitPerChannel(public = 3.seconds))
val pnConfiguration = PNConfiguration.builder(userId = UserId("myUserId"), subscribeKey = "mySubscribeKey").build()

Chat.init(chatConfig, pnConfiguration).async { result ->
    result.onSuccess { chat: Chat ->
        println("Chat successfully initialized")
    }.onFailure { exception: PubNubException ->
        println("Exception initialising chat: ${exception.message}")
    }
}
```

#### Custom payload

When [initializing Chat SDK](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/configuration#initialize-pubnub), you can pass your custom message payload structure using the [customPayloads](#input-parameters) object and related properties. This lets Chat SDK correctly interpret your app's messages when sending and receiving them.

##### Define custom payload for all channels

If your app uses the `my.custom.payload.structure.text` structure instead of the default `message.text` format, pass your custom payload to all channels. Additionally, define your custom action names to be added to messages when they're edited or deleted.

```kotlin
ChatConfiguration(
    customPayloads = CustomPayloads(
        getMessagePublishBody = { content, _, _ ->
            mapOf(
                "custom" to mapOf(
                    "payload" to mapOf(
                        "text" to content.text
                    )
                ),
                // optionally also save files and type: "files" to content.files
            )
        },
        getMessageResponseBody = { json: JsonElement, _, _ ->
            EventContent.TextMessageContent(
                json.asJsonObject?.getAsJsonObject("custom")?.getAsJsonObject("payload")?.getAsJsonObject("text")?.asString ?: error("Message cannot be parsed"),
                // optionally parse files
            )
        }
    )
)
```

##### Define custom payload for one channel

If your app uses the `my.custom.payload.structure.text` structure instead of the default `message.text` format for `support-channel`, pass your custom payload to that channel. Additionally, define your custom action names to be added to messages when they're edited or deleted.

The code sets up a PubNub chat instance with specific handlers for processing message payloads differently based on the channel.

```kotlin
var chat: Chat
val customPayloads: CustomPayloads = CustomPayloads(
    getMessagePublishBody = { content, channelId, defaultMessagePublishBody ->
        // Define which channel should use custom payload
        if (channelId == "support-channel") {
            mapOf(
                "custom" to mapOf(
                    "payload" to mapOf(
                        "text" to content.text
                    )
                ),
                "files" to content.files
            )
        } else {
            // The rest of the channels will use the default Chat SDK message body structure
            defaultMessagePublishBody(content)
        }

    },
    getMessageResponseBody = { json: JsonElement, channelId, defaultMessageResponseBody ->
        if (channelId === "support-channel") {
            EventContent.TextMessageContent(
                json.asMap()?.get("custom")?.asMap()?.get("payload")?.asMap()?.get("text")?.asString()!!,
                json.asMap()?.get("files")?.asList()?.map {
                    File(
                        it.asMap()?.get("name")?.asString()!!,
                        it.asMap()?.get("id")?.asString()!!,
                        it.asMap()?.get("url")?.asString()!!,
                        it.asMap()?.get("type")?.asString(),
                    )
                }
            )
        }else{
            defaultMessageResponseBody(json)
        }
    },
    // Override the default Chat SDK action type for editing a message ("edited") with your own name
    editMessageActionName = "updated",
    // Override the default Chat SDK action type for deleting a message ("deleted") with your own name
    deleteMessageActionName = "removed"
)
val chatConfig = ChatConfiguration(logLevel = LogLevel.OFF, customPayloads = customPayloads)
val builder = PNConfiguration.builder(userId = UserId("myUserId"), subscribeKey = "mySubscribekey") {
    publishKey = "myPublishKey"
}
val pnConfiguration = builder.build()
Chat.init(chatConfig, pnConfiguration).async { result ->
    result.onSuccess { createdChat: Chat ->
        chat = createdChat
    }.onFailure { exception: PubNubException ->
        println("Exception initialising chat: ${exception.message}")
    }
}
```

## Destroy Chat instance

Use the `destroy()` method to release all resources held by the `Chat` instance and the underlying PubNub SDK instance. Call this when your app shuts down or when you no longer need the Chat SDK — for example, on user logout or component unmount.

### Method signature

```kotlin
chat.destroy()
```

### Input

None.

### Output

None. This is a fire-and-forget cleanup method.

### Sample code

```kotlin
// Clean up resources when the app shuts down or the user logs out
chat.destroy()
```

## Next steps

After initialization, you can:

* Create [channels](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/create) and [users](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/create)
* Add features like [messaging](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/messages/send-receive), [typing indicators](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/channels/typing-indicator), and [presence](https://www.pubnub.com/docs/chat/kotlin-chat-sdk/build/features/users/presence)