JavaScript Client SDK

Installation

Install with a package manager like npm or yarn.

$ yarn add @pusher/chatkit

Then import into your code like you would any other module.

If you are using the SDK in a react native app use @pusher/chatkit/react-native
import { ChatManager, TokenProvider } from '@pusher/chatkit'

Or download directly from unpkg using a script tag in the head of your document:

<script src="https://unpkg.com/@pusher/chatkit"></script>

This will make the SDK available at window.Chatkit.

Instantiate Chatkit

To get started with Chatkit you will need to instantiate both a ChatManager instance as well as a TokenProvider instance to authenticate users. The example below uses demo credentials.

JAVASCRIPT

1
2
3
4
5
const chatManager = new ChatManager({
  instanceLocator: 'v1:us1:80215247-1df3-4956-8ba8-9744ffd12161',
  userId: 'sarah',
  tokenProvider: new TokenProvider({ url: 'your.auth.url' })
})

You can see this in action online here CodePen Demo

Chat Manager

JAVASCRIPT

1
2
3
4
5
const chatManager = new ChatManager({
  instanceLocator: 'v1:us1:80215247-1df3-4956-8ba8-9744ffd12161',
  userId: 'sarah',
  tokenProvider: new TokenProvider({ url: 'your.auth.url' })
})
Note that the user ID provided to the Chat Manager must represent a user that already exists, see the Server SDK docs for details on creating users.

ChatManager Arguments

The ChatManager constructor takes a single options object with the following properties.

ArgumentTypeDescription
instanceLocatorstring (required)Get this from your dashboard.
userIdstring (required)The ID of the user that you wish to connect to Chatkit as. This will also be passed to the token provider and included in token requests as a query parameter in the form: user_id=<USER_ID>.
tokenProviderTokenProvider (required)Used to retrieve tokens to authenticate requests made to the Chatkit servers. See Token Provider.
loggerLogger (optional)A cutom logger implementation. See Logger.
connectionTimeoutnumber (optional)The number of milliseconds to wait before timing out a connection attempt with an error. Defaults to 10s.

Methods

MethodDescription
connectCreates a connection between your client and a the Chatkit servers. See Connect for more information.

TokenProvider

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
11
const tokenProvider = new TokenProvider({
  url: 'your.auth.url',
  queryParams: {
    someKey: someValue,
    ...
  },
  headers: {
    SomeHeader: 'some-value',
    ...
  }
})

TokenProvider Arguments

The TokenProvider constructor takes a single options object with the following properties.

ArgumentTypeDescription
urlstring (required)The URL that the ChatManager should make a POST request to in order to fetch a valid token. This will be either the test token provider or your own custom auth endpoint.
queryParamsobject (optional)An object of key–value pairs to be passed as query parameters along with the token request.
headersobject (optional)An object of key–value pairs to be passed as headers along with the token request.

When making requests to a token endpoint, the TokenProvider expects the response to have the following format:

JSON

1
2
3
4
{
  "access_token": "<your token here>",
  "expires_in": "<seconds until token expiry here>"
}
For more information on the auth process please refer to the authentication docs.

Connect

JAVASCRIPT

1
2
3
4
5
6
7
chatManager.connect()
  .then(currentUser => {
    console.log('Successful connection', currentUser)
  })
  .catch(err => {
    console.log('Error on connection', err)
  })

Once you’ve initialized your Chat Manager you are ready to connect to the Chatkit servers. The connect method returns a promise that resolves with a Current User object. This object is your primary means of interacting with the Chatkit instance, rooms, messages and users.

Connection Hooks

JAVASCRIPT

1
2
3
4
5
chatManager.connect({
  onAddedToRoom: room => {
    console.log(`Added to room ${room.name}`)
  }
})

When connecting you can also provide hooks to be notified when various events happen. For example, if you wish to be notified when the connected user gets added to a room, you could provide theonAddedToRoom hook.

HookAcceptsDescription
onAddedToRoomroomThe current user is added to a room.
onRemovedFromRoomroomThe current user is removed from a room.
onRoomUpdatedroomA room that the current user is a member of has changed name.
onRoomDeletedroomA room that the current user is a member of is deleted.

The following can also be provided as connection or as hooks for a given room.

HookAcceptsDescription
onUserStartedTypingroom, userA user started typing in a room in which the current user is a member.
onUserStoppedTypingroom, userA user stopped typing in a room in which the current user is a member.
onUserJoinedRoomroom, userA user joined a room in which the current user is a member.
onUserLeftRoomroom, userA user left a room in which the current user is a member.
onUserCameOnlineuserA user came online.
onUserWentOfflineuserA user went offline.
onNewReadCursorcursorA new read rursor was set for the current user.

Current User

When an initial connection is successfully made to Chatkit the client will receive a CurrentUser object. The CurrentUser object is the primary means of interacting with Chatkit.

User Properties

PropertyTypeDescription
roomsarrayThe rooms that the connected user is a member of. See rooms.
usersarrayThe users that share a common room membership with the connected user. See users.
roomSubscriptionsobjectThe rooms a user is joined and subscribed to. See subscribe to a room.

Disconnect

To disconnect the current user from all subscriptions. Call the disconnect method on the CurrentUser object.

Rooms

There are a few important things to remember about Chatkit rooms; they are either public or private, users that are members of a room can change over time, all chat messages belong to a room.

Room Properties

PropertyTypeDescription
idintThe global identifier for the room on the instance.
isPrivateboolIf true the room is private, otherwise the room is public.
namestringThe human readable name of the room (this needn’t be unique!)
usersarrayAn array of all the users that are members of this room. See Users.

Create a Room

All that you need to provide when creating a room is a name. The user that creates the room will automatically be added as a member of the room. The following code will create a public room called general. A room name must be no longer than 60 characters.

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
currentUser.createRoom({
  name: 'general',
  private: true,
  addUserIds: ['craig', 'kate']
}).then(room => {
  console.log(`Created room called ${room.name}`)
})
.catch(err => {
  console.log(`Error creating room ${err}`)
})

All rooms are public by default. You can customise the new room by passing in options at the point of creation. To create a private room you need to set the private option to true. You can add other users to a room by specifying their IDs with the addUserIds option.

Fetch Messages From a Room

You can fetch up to the last 100 messages added to a room when you subscribe but sometimes you’ll want to fetch older messages. For example, suppose you subscribe to a room and the oldest message you see has the ID 42. To see older messages, you can provide the initialId option to the fetchMessages method.

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
11
12
currentUser.fetchMessages({
  roomId: someRoomId,
  initialId: 42,
  direction: 'older',
  limit: 10,
})
  .then(messages => {
    // do something with the messages
  })
  .catch(err => {
    console.log(`Error fetching messages: ${err}`)
  })

Here we assume that either the oldest message ID that has been received so far (42 in the above example) is being tracked in a variable or calculated dynamically. For example if roomMessages keeps track of all messages received from a given room:

1
const oldestMessageIdReceived = Math.min(...roomMessages.map(m => m.id))

The full set of options follows:

PropertyTypeDescription
initialIdint (optional)A message ID that defaults to the most recent message ID.
directionstring (optional)Defaults to older which will backwards fetch messages but can be set to newer if you want to forward fetch messages.
limitint (optional)The amount of messages you want to revieve, which defaults to 20 and has a maximum 100.

Messages are fetched in chronological order, starting at the initialId and moving forwards or backwards until there are either no more messages, or the limit is reached.

Add a User to a Room

The current user can add users to rooms that they themselves are a member of.

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
currentUser.addUserToRoom({
  userId: 'keith',
  roomId: 123
})
  .then(() => {
    console.log('Added keith to room 123')
  }),
  .catch(err => {
    console.log(`Error adding keith to room 123: ${err}`)
  })

Remove a User From a Room

The current user can remove users from rooms that they themselves are a member of.

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
currentUser.removeUserFromRoom({
  userId: 'leah',
  roomId: 123
})
  .then(() => {
    console.log('Removed leah from room 123')
  })
  .catch(err => {
    console.log(`Error removing leah from room 123: ${err}`)
  })

Get Joinable Rooms

To fetch an array of the rooms that a user is able to join (but isn’t yet a member of):

JAVASCRIPT

1
2
3
4
5
6
7
currentUser.getJoinableRooms()
  .then(rooms => {
    // do something with the rooms
  })
  .catch(err => {
    console.log(`Error getting joinable rooms: ${err}`)
  })

The rooms returned will be an array of the public rooms which the currentUser is not a member of.

Join a Room

Join a room with ID someRoomId:

JAVASCRIPT

1
2
3
4
5
6
7
currentUser.joinRoom({ roomId: someRoomID })
  .then(room => {
    console.log(`Joined room with ID: ${room.id}`)
  })
  .catch(err => {
    console.log(`Error joining room ${someRoomID}: ${err}`)
  })

Leave a Room

Leave a room with ID someRoomId:

JAVASCRIPT

1
2
3
4
5
6
7
currentUser.leaveRoom({ roomId: someRoomID })
  .then(room => {
    console.log(`Left room with ID: ${room.id}`)
  })
  .catch(err => {
    console.log(`Error leaving room ${someRoomID}: ${err}`)
  })

Update a Room

Change the name and or privacy of a room with ID someRoomId:

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
11
currentUser.updateRoom({
  roomId: someRoomID,
  name: 'Some updated name',
  private: false
})
  .then(() => {
    console.log(`Updated room with ID: ${someRoomID}`)
  })
  .catch(err => {
    console.log(`Error updated room ${someRoomID}: ${err}`)
  })

All other connected memebers of the room will receive an event that informs them that the room has been updated. Note that the current user must have the room:update permission to use this method.

Delete a Room

Delete a room with ID someRoomId:

JAVASCRIPT

1
2
3
4
5
6
7
currentUser.deleteRoom({ roomId: someRoomID })
  .then(() => {
    console.log(`Deleted room with ID: ${someRoomID}`)
  })
  .catch(err => {
    console.log(`Error deleted room ${someRoomID}: ${err}`)
  })

All other connected memebers of the room will receive an event that informs them that the room has been deleted. Any attempts to interact with a deleted room will result in an error. Note that the current user must have the room:delete permission to use this method.

When a room is deleted, all of its associated messages are deleted as well.

Subscriptions

To be notified when new messages are added to a room, you’ll need to subscribe to it and provide a onNewMessage hook. (Too see the full list of possible hooks see Room Subscription Hooks). At most 100 recent messages can be retrieved on subscription, to fetch older messages see Fetch Messages From a Room. To receive only new messages, set the third parameter to 0.

JAVASCRIPT

1
2
3
4
5
6
7
8
9
currentUser.subscribeToRoom({
  roomId: someRoomId,
  hooks: {
    onNewMessage: message => {
      console.log(`Received new message ${message.text}`)
    }
  },
  messageLimit: 10
})
Subscribing implicitly joins a room if you aren’t already a member. Subscribing to the same room twice will cause the existing subscription to be cancelled and replaced by the new one.

By default when you subscribe to a room you will receive up to the 20 most recent messages that have been added to the room. The number of recent messages to fetch can be configured by setting the third parameter to subscribeToRoom. These recent messages will be passed to the onNewMessage callback in the order they were sent, just as if they were being sent for the first time.

Room Subscription Hooks

The full list of hooks that can be provided as options to the subscribeToRoom method are as follows:

HookAcceptsDescription
onNewMessagemessageA new message has been added to the room.
onUserStartedTypinguserA user started typing in the room.
onUserStoppedTypinguserA user stopped typing in the room.
onUserJoineduserA user joined the room.
onUserLeftuserA user left the room.
onUserCameOnlineuserA member of the room came online.
onUserWentOfflineuserA member of the room went offline.
onNewReadCursorcursorA member of the room set a new read rursor.

Cancel a Subscription

Call the cancel method on a room subscription if you no longer want to receive events from that room. You can find room subscriptions indexed by room ID in the roomSubscriptions property of the Current User object.

1
currentUser.roomSubscriptions[roomId].cancel()

Users

User objects can be found in various places: globally under currentUser.users, scoped by room under room.users, or returned as the argument to some hooks.

Users Properties

AttributeTypeDescription
idstringThe unique identifier for the user on the instance.
namestringThe human readable name of the user. This is not required to be unique.
avatarURLstringThe location (url) of an avatar for the user.
presenceobjectAn object containing information regarding the users presence state. See user presence.

Messages

Every message belongs to a Room and has an associated sender, which is represented by a User object. Files can be sent along with a messages by specifying an Attachment property.

Message Properties

AttributeTypeDescription
idintThe ID assigned to the message by the Chatkit servers.
textstringThe text content of the message if present.
attachmentAttachmentThe message’s attachment if present.
senderUserThe user who sent the message.
roomRoomThe room to which the message belongs.
createdAtstringThe timestamp at which the message was created.
updatedAtstringThe timestamp at which the message was last updated.

Sending a Message

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
currentUser.sendMessage({
  text: "Hi there!",
  roomId: myRoom.id
})
.then(messageId => {
  console.log(`Added message to ${myRoom.name}`)
}),
.catch(err => {
  console.log(`Error adding message to ${myRoom.name}: ${err}`)
})

An attachment can be added when you send a message. This can be done in one of two ways:

1. Provide some data (of type File or Blob, most likely) along with a name for the data that will be used as the name of the file that is stored by the Chatkit servers.

This is how you send a message with an attachment of this kind:

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
currentUser.sendMessage({
  text: "Hi there!",
  roomId: myRoom.id
  attachment: { // optional
    file: document.querySelector("input[name=file]").files[0],
    name: "myfile.jpg"
  }
})
.then(messageId => {
  console.log(`Added message to ${myRoom.name}`)
},
.catch(err => {
  console.log(`Error adding message to ${myRoom.name}: ${err}`)
})

Note that the resulting type will be inferred automatically by Chatkit servers. If the type of the file is unable to be determined then it will be given a type of file.

2. Provide a link along with a type that describes the attachment. As above, this would be one of image, video, audio, or file.

This is how you send a message with an attachment of this kind:

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
11
12
13
14
currentUser.sendMessage({
  text: "Hi there!",
  roomId: myRoom.id,
  attachment: {
    link: "https://cataas.com/cat",
    type: "image"
  }
})
.then(messageId => {
  console.log(`Added message to ${myRoom.name}`)
},
.catch(err => {
  console.log(`Error adding message to ${myRoom.name}: ${err}`)
})

Attachment

It is possible for users to attach files to messages. If a message has an attachment you will most likely have to fetch it before you can use it. This will give you the actual URL of the resource.

Attachment Properties

AttributeTypeDescription
linkstringThe link representing the location of the attachment.
typestringThe type of the attachment; one of image, video, audio, or file.
fetchRequiredboolIf the attachment link needs to be fetched from the Chatkit servers; see Fetch an Attachment.

Fetching an Attachment

If a message contains an attachment with the fetchRequired property set to true, then attachment.link cannot be used directly. We must first fetch the URL of the attachment itself using fetchAttachment.

JAVASCRIPT

1
2
3
4
5
6
7
currentUser.fetchAttachment({ url: attachment.link })
  .then(url => {
    // do something with the url
  })
  .catch(err => {
    console.log('Error fetching attachment:', err)
  })

Typing Indicators

Sometimes it’s useful to be able to see if another user is typing. You can use Chatkit to let all the connected members of a room know when another user is typing.

Trigger a Typing Event

To send typing indicator events call isTypingIn with the ID of the room the current user is typing in.

JAVASCRIPT

1
2
3
4
5
6
7
currentUser.isTypingIn({ roomId: someRoomId })
  .then(() => {
    console.log('Success!')
  })
  .catch(err => {
    console.log(`Error sending typing indicator: ${err}`)
  })

Receive Typing Indicator Events

To be notified when a user starts or stops typing in a room, provide a onUserStartedTyping and a onUserStoppedTyping function as part of the room subscription hooks.

JAVASCRIPT

1
2
3
4
5
6
onUserStartedTyping: user => {
  console.log(`User ${user.name} started typing`)
},
onUserStoppedTyping: user => {
  console.log(`User ${user.name} stopped typing`)
}

When a user starts or stops typing, these functions will be called with the corresponding user object.

User Presence

If a user has at least one active connection to the Chatkit service then they are considered online. When a user has no active connections they are considered offline. Each user object keeps track of whether a user is online or offline via the presence property.

JAVASCRIPT

1
2
3
if (user.presence.state === 'online') {
  // The user is online! Show an online badge or something...
}

Additionally, to be notified when a user comes online or goes offline, you can provide the onUserCameOnline and onUserWentOffline hooks. Either at the room level – fires whenever a member of that room goes on or off line, or at the connection level – fires whenever any users sharing a common room membership go on or offline.

JAVASCRIPT

1
2
3
4
5
6
onUserCameOnline: (user) => {
  console.log(`User ${user.name} came online`)
},
onUserWentOffline: (user) => {
  console.log(`User ${user.name} went offline`)
}

Cursors

Read cursors track how far a user has read through the messages in a room. Each read cursor belongs to a user and a room – represented by a Cursor object.

Cursor Properties

AttributeTypeDescription
positionintThe message ID that the user has read up to.
updatedAtstringThe timestamp when the cursor was last set.
roomRoomThe room that the cursor refers to.
userUserThe user that the cursor belongs to.
typeintThe type of the cursor object, currently always 0 (representing a read cursor).

Setting a Cursor

When you are confident that the current user has “read” a message, call setReadCursor with a roomId and a position (the ID of the newest message that has been “read”).

JAVASCRIPT

1
2
3
4
5
6
7
8
9
10
currentUser.setReadCursor({
  roomId: someRoomId,
  position: someMessageId
})
  .then(() => {
    console.log('Success!')
  })
  .catch(err => {
    console.log(`Error setting cursor: ${err}`)
  })

Getting a Cursor

The current user’s read cursors are available immediately upon connecting. Access any existing cursors with the readCursor method. (A cursor that hasn’t been set yet is undefined.)

JAVASCRIPT

1
2
3
4
5
6
7
8
const cursor = currentUser.readCursor({
  roomId: someRoomId
})
console.log(`read up to message ID ${
  cursor.position
} in ${
  cursor.room.name
}.`)
To be notified when any of the current user’s read cursors are changed, supply an onNewReadCursor hook on connection.

Access Other User’s Cursors

After subscribing to a room, read cursors for members of that room can be accessed by supplying a userId as the second parameter to the readCursor method.

JAVASCRIPT

1
2
3
4
5
6
7
8
9
const alicesCursor = currentUser.readCursor({
  roomId: someRoomId,
  userId: 'alice'
})
console.log(`Alice has read up to ${
  alicesCursor.position
} in ${
  alicesCursor.room.name
}.`)
To be notified when any member of the room changes their read cursor, supply an onNewReadCursor hook when subscribing to the room.

Logger

A custom logger can be provided that implements all of the following functions.

JAVASCRIPT

1
2
3
4
5
6
7
{
  verbose: (...args) => console.log('verbose:', ...args),
  debug: (...args) => console.log('debug:', ...args),
  info: (...args) => console.log('info:', ...args),
  warn: (...args) => console.log('warn:', ...args),
  error: (...args) => console.log('error:', ...args)
}

Did you find this document useful?

We are always striving to create the most accurate and informative docs as possible. If there is something especially wrong (or right) here then please let us know.