🎉 New! Web Push Notifications for Chatkit. Learn more in our latest blog post.

Extensible API for in-app chat


Build scalable realtime features


Programmatic push notifications



Read the docs to learn how to use our products


Explore our tutorials to build apps with Pusher products


Reach out to our support team for help and advice

Sign in
Sign up

Migrating from SendBird to Chatkit

  • Wern Ancheta

July 2nd, 2019
You need basic knowledge of JavaScript and SendBird.

In this tutorial, I’ll show you how you can get started with the migration process. We’ll take a look at some SendBird SDK code and translate it to the Chatkit equivalent. Along the way, I’ll highlight some of the key differences between SendBird and Chatkit which you should be aware of.


Basic knowledge of JavaScript and SendBird is required to follow this tutorial.

The migration process

We’ll take a look at the following steps in migrating your SendBird app to Chatkit:

  1. Creating a Chatkit app instance.
  2. Installing the dependencies.
  3. Migrating the code.
  4. Exporting the messages from SendBird and importing them to Chatkit.

Creating a Chatkit app

The first step is for you to create a new Chatkit app instance:

The Credentials tab is where you’ll find the application keys you can use for connecting to Chatkit. The equivalent of this in SendBird can be found on your app’s dashboard overview page:

Test token provider

If you scroll down on that same page, you’ll see the section for the test token provider. SendBird has no equivalent feature for this because everything is done on their server.

In Chatkit, it is used to authenticate the user. The test token provider is a server which does this for you. It’s called “test” because you shouldn’t use this feature for production. You can enable this feature for now while migrating your app. This should show the URL you can point your app to when authenticating your users:

You can learn more about authentication on this page.


The console is where you can create the users, rooms, and roles in your app. This is an indispensable tool to have in the migration process. It’s specifically useful for testing your integration because you can even create messages from here.

To start using it, you first have to create a new user. You can treat this user as the admin so you can use root for its user ID and username:

Once a user is created, you can start exploring. You can probably learn most of what Chatkit has to offer just by playing with the console:

After looking around the UI for a bit, you’ll notice that Chatkit has no concept of channels (Open Channel and Group Channel). Instead, what you have are rooms. Rooms can either be public or private. The main difference between the two is that users can freely join public rooms. Public rooms which the user haven’t joined yet can be listed by using the getJoinableRooms() method. From there, you can use the joinRoom() method to join the room.

On the other hand, private rooms cannot be listed publicly and they also can’t be joined from the client side. You’ll have to use one of the server SDKs to get a list of all rooms by using the getRooms() method. After that, you can use the addUsersToRoom() method to add the user to the room.

Unlike SendBird, Chatkit currently has no feature for inviting users into a room. So you’ll have to implement it on your own. For example, you can send a push notification to invite a user into a room. When the user clicks on it, they’ll be redirected to a page which asks whether they want to accept the invitation or not. If they accept, then you can use the addUsersToRoom() method to manually add them to the room.

A feature that doesn’t exist in SendBird, however, are the roles and permissions. It’s primarily used to restrict what each member can do in all rooms or a specific room. For example, you want to restrict new members from uploading files or seeing the typing indicators.

You can check out the documentation on roles and permissions for more information.


If your existing SendBird chat app is using push notifications, the Chatkit equivalent is Webhooks. Click on the Settings tab and click on the ADD A WEBHOOK button to view the interface below:

The UI above allows you to set a URL to which Chatkit will send the data regarding a specific event that happened in your app. The events are in the Triggers section. You just have to enable them for your server to get notified. Be sure to also supply a value to the WEBHOOK SECRET and verify the requests to ensure it’s really coming from Chatkit’s servers.

Once you’ve added the code for accepting the requests coming from the webhooks, you can click on the Push Notifications tab to set up push notifications:

Unfortunately, at the time of writing this tutorial, only Native Android and iOS are supported. So if you don’t know anything about native mobile app development (Java, Kotlin, or Swift), then your only option is to use Firebase and the React Native Push Notification library.

Installing the dependencies

In this section, we’ll install the dependencies required when migrating the existing SendBird chat app. This assumes that you’ve already uninstalled the SendBird dependencies in your project.

In your project, you can install Chatkit by executing the following command:

    yarn add @pusher/chatkit-client

Migrating the code

Now we’re ready to migrate the code to use Chatkit. Before we get started, note that this won’t be your usual line by line tutorial. To keep things context-free, I’ll just be showing code samples in JavaScript. In the GitHub repo, the sendbird branch contains the code for the chat app before it was migrated, while the chatkit branch contains the code after it was migrated.

Connecting to Chatkit

To use Chatkit, you need to extract the ChatManager and TokenProvider from the Chatkit client:

    // import SendBird from "sendbird";
    import { ChatManager, TokenProvider } from "@pusher/chatkit-client";

To connect to SendBird, you usually do this:

    // Sendbird
    const sb = new SendBird({ 'appId': 'YOUR SENDBIRD APP ID' });
    sb.connect("YOUR USER'S UNIQUE USERNAME", (user, error) => {
      if (!error) {
        // ... 

To connect to Chatkit, you do this instead:

    // Chatkit
    const chatManager = new ChatManager({
      instanceLocator: CHATKIT_INSTANCE_LOCATOR_ID,
      userId: "YOUR USER'S UNIQUE ID",
      tokenProvider: new TokenProvider({ url: 'YOUR TOKEN PROVIDER URL' }) // can be your test token provider for now

    const currentUser = await chatManager.connect();

As you can see, the main difference between the two is the use of username versus user ID. Their purpose is essentially the same: to uniquely identify the user that’s currently using the service. But as mentioned earlier, Chatkit also has this token provider which you run on your own server to verify if the user is really a user of your app. Chatkit assumes that you have an existing database of users (either on your own server or using a service like Auth0).

Although the users in the console are mainly for Chatkit’s use only, if your app is only a casual chatting app with no need for authentication, you can probably stick with the utility provided by Chatkit.

Getting a list of rooms

Once the user is connected, in SendBird, the list of channels can be fetched using either the createOpenChannelListQuery() or createMyGroupChannelListQuery() methods:

    // Sendbird
    const channelListQuery = sb.OpenChannel.createOpenChannelListQuery();

    if (channelListQuery.hasNext) {
      channelListQuery.next((channelList, error) => {
        if (!error) {
          // get channel URL... 

In Chatkit, you can use the getJoinableRooms() method to get the list of public rooms that the user hasn’t joined yet:

    // Chatkit
    const rooms = await currentUser.getJoinableRooms();

If you also need to get a list of private rooms, you’ll have to use the getRooms() method from the server. Be sure to set the includePrivate option to true so it also returns the private rooms.

Entering a room

The next step is entering the room which the user has selected. In SendBird, you do it like so:

    // Sendbird
    sb.OpenChannel.getChannel("YOUR CHANNEL URL", (channel, error) => {
      if (!error) {
        channel.enter((response, error) => {
          if (!error) {
            const messageListQuery = channel.createPreviousMessageListQuery();
            messageListQuery.limit = 10;
            messageListQuery.load((messageList, error) => {
              if (!error) {
                messageList.forEach((message_data) => {
                  // add messages to the UI...

In Chatkit, you use the reference to the currentUser to call the subscribeToRoomMultipart() method to subscribe to the room. This allows you to subscribe to hooks such as onMessage to get notified every time a new message is sent in the room:

    // Chatkit
    await currentUser.subscribeToRoomMultipart({
      roomId: "YOUR ROOM ID",
      hooks: {
        onMessage: this.onReceive
      messageLimit: 10 // number of initial messages to fetch

In the SendBird code earlier, we had to query for the last ten messages sent in the room using the createPreviousMessageListQuery() method. In Chatkit, there’s no need to do that because the onMessage hook gets automatically executed when you subscribe to a room. The messageLimit allows you to specify how many messages to initially fetch, so by default, the onMessage hook gets called ten times when you subscribe to a room.

There are other useful room subscription hooks which you can use such as onUserStartedTyping, onUserJoined, and onPresenceChanged. Note that unlike SendBird, you can actually attach all of the hooks to any type of room. In SendBird, you’re only able to listen for typing indicators and other events on a Group Channel.

Receiving messages

In SendBird, a channel event handler is used to subscribe to different events in the room. One of those events is the onMessageReceived event which gets triggered every time another user sends a message in the room:

    // Sendbird
    const channelHandler = new sb.ChannelHandler();
    channelHandler.onMessageReceived = (channel, message) => {
      if (channel.url === this.room_url) {
        // add message to the UI

In Chatkit, as mentioned earlier, has a similar idea in the form of hooks. All you have to do is supply those hooks a function that they can execute when they’re received in the app:

    // Chatkit
    onReceive = (data) => {
      // add message to the UI

The main difference between SendBird’s new message handler and Chatkit is that SendBird only triggers it if another user sent the message (someone other than the one who is currently logged in). This means that in order to add the new message to the UI, you’ll have to call the same function that you’re using to append messages to the UI when sending a message.

In Chatkit, the onMessage hook gets triggered no matter who sent the message. So we can actually append the new message to the UI from there.

Sending messages

Sending messages in SendBird looks something like this:

    // Sendbird
    channel.sendUserMessage("YOUR MESSAGE", (message, error) => {
      if (!error) {
        // append message to the UI...

In Chatkit, it looks like this:

    // Chatkit
    let message_parts = [
      { type: "text/plain", content: "YOUR MESSAGE" }

    await this.currentUser.sendMultipartMessage({
      roomId: "YOUR ROOM ID",
      parts: message_parts

Messages in Chatkit has multiple parts. This is because the API allows us to add other types of data in the message. Files for example. It’s good practice to always set the first part to the actual text message. That way, when you handle their receipt, you can always expect to find the text message on the first index.

Loading earlier messages

In SendBird, you load messages that are previously sent in the room by using the getPreviousMessagesByTimestamp() method. This accepts the timestamp of your reference message:

    // Sendbird
    const earliest_message_timestamp = Math.min(
      ...messages.map(m => parseInt(m.timestamp))

    channel.getPreviousMessagesByTimestamp(earliest_message_timestamp, false, 10, true, 0, '', (messages, error) => {
      if (!error && messages.length > 0) {    
        let earlier_messages = [];
        messages.forEach((message_data) => {

The equivalent of this in Chatkit is the fetchMultipartMessages() method. Instead of the timestamp, it accepts the ID of your reference message. Then you can specify the direction to older so that messages fetched backwards. So if the initialId you specified is 10, it’s going to fetch 9, 8, 7, and so on. Which means you’ll have to reverse its ordering if you want to prepend them to the existing message list:

    const earliest_message_id = Math.min(
      ...messages.map(m => parseInt(m._id))

    let messages = await currentUser.fetchMultipartMessages({
      roomId: "YOUR ROOM ID",
      initialId: earliest_message_id,
      direction: "older",
      limit: 10

    let earlier_messages = [];
    messages.forEach((msg) => {

Exporting the messages from SendBird and importing them to Chatkit

If you have an existing user base, the final step in the migration process is for you to export all the existing messages from SendBird and import them to Chatkit.

On your SendBird dashboard, you can click on the Messages tab to view all the messages sent by all of your users. From here, you can download the messages in JSON format:

You can find more information about the export feature on the SendBird blog.

Once you have all the messages in a JSON file, you can start importing them to Chatkit. Unfortunately, at the time of writing of this tutorial, Chatkit doesn’t have a message import feature yet. So you’ll have to implement it on your own using the HTTP API or one of the server SDKs:

Pick one based on your current stack to make the migration process smoother.

Importing messages is out of the scope of this tutorial, so I’ll leave its implementation to you. For starters, you’ll probably be going to need to make a call to the following endpoints:

  • Create user
  • Create room
  • Send message - it’s currently limited to sending a message so you have no control over its timestamp. A hacky way to deal with this is to monkey patch the Date constructor (if you’re using Node) to use whatever time the original message was sent.


In this tutorial, you’ve seen how easy it is to migrate from SendBird to Chatkit. You also learned some of the key differences between SendBird and Chatkit. Knowing those differences should make your migration process smoother.

If you need help in using Chatkit, the documentation is always a good place to start. If you’re looking for a feature that’s available to SendBird which isn’t on Chatkit, you can check the issues on either the client or the server. Someone else might have already looked for the same feature in there.

As always, you can find the code used in this tutorial on this GitHub repo.

Clone the project repository
  • Chat
  • JavaScript
  • Chatkit


  • Channels
  • Chatkit
  • Beams

© 2020 Pusher Ltd. All rights reserved.

Pusher Limited is a company registered in England and Wales (No. 07489873) whose registered office is at 160 Old Street, London, EC1V 9BW.