Sample chat app

We've created a sample direct (1:1) chat app to show you what you can use our Chat SDK for.

Underneath, the app uses a set of basic Chat SDK methods to initialize the SDK, create a sample channel and users, and let you send messages. On the outside, the app comes with a custom UI layer added to show what a final chat app could look like - how you present your own apps, however, is entirely up to you.

Run and test the app first, then read on to understand how it works.


Tools used


To run the chat app, make sure to have the following:

  • yarn (>=1.22.19)

  • Node.js (>=18.10.0)

  • Code editor (for example, Visual Studio Code)

  • Publish and subscribe keys to initialize the PubNub object in your app and send and receive messages through the PubNub Network.

    Keys setup and configuration

    To get both keys, sign in or create an account on the Admin Portal. The autogenerated Demo Keyset in My First App already contains the configuration required to complete this guide (enabled App Context and selected region closest to your location). Follow this guide if you need help creating the keys.

Run the chat app

Check how to set up a 1:1 chat app by running a ready sample React app or adding the Chat SDK to your own app.

  1. Download the getting-started app from the js-chat repository - the monorepo that houses the source code of the Chat SDK.

  2. Unpack the archive into the folder of your choice.

  3. Open the terminal, navigate to the js-chat-master root folder, and install the dependencies.

  4. Go to the lib folder that contains the TypeScript sources.

    cd lib
  5. Build the app.

    yarn build
  6. Go to the samples/getting-started folder with the app's source code.

    cd ../samples/getting-started
  7. Add required configuration.

    Open the app in the code editor and navigate to the .env.example file under samples/getting-started. Duplicate the file in the same location, rename the copy to .env, and use it to specify values for your publish and subscribe keys from your app's keyset on the Admin Portal.

    // for example: VITE_PUBNUB_PUB_KEY=pub-c-jbgh67-a796-c36-z81-17dvbf4
    // for example: VITE_PUBNUB_SUB_KEY=sub-c-jb46h67-z796-g36-z91-19vdfb1

    Both keys are referenced in the src/App.tsx file containing the whole app's source code.

    const chat = await Chat.init({
    publishKey: import.meta.env.VITE_PUBNUB_PUB_KEY,
    subscribeKey: import.meta.env.VITE_PUBNUB_SUB_KEY,
    userId: randomizedUsers[0].id,

    To associate a sender/current user with the PubNub messages, you must configure the userId parameter for your user ID in the database. If you wish, modify the default value for the chat user.

    For simplicity, the getting started app sets a static userId that randomly selects one of the two default users (to simulate a 1:1 conversation). However, if you implement chat in your app, you should generate a userId per user, device, and server and reuse it for their lifetime. Using separate User IDs in real-life apps is particularly important as it impacts your overall billing and the way your app works.

  8. Run the app in the terminal.

    yarn dev
  9. When the app compiles successfully, you will see the link to the localhost in the terminal.

  10. You can open the app in two separate browser windows - if you get randomly assigned two different users, simulate a real-life chat conversation.

    A sample conversation between a support agent and a customer may look as follows:

Sample chat

How this works

Let's walk you through all the Chat SDK methods this app uses to show you what you need to create your own chat. This section analyzes the src/App.tsx file that contains the app's source file.

Initialize chat

Initialize Chat SDK, providing your publish and subscribe keys from the Admin Portal.

const chat = await Chat.init({
subscribeKey: import.meta.env.VITE_PUBNUB_SUB_KEY,
publishKey: import.meta.env.VITE_PUBNUB_PUB_KEY,
userId: randomizedUsers[0].id,

For this app, you must set these envs for VITE_PUBNUB_SUB_KEY and VITE_PUBNUB_PUB_KEY in the separate .env file (copy of the .env.example file).

Set up users

This sample app uses two hardcoded sample users - a support agent and a customer.

const userData = [
id: "support-agent",
data: { name: "John (Support Agent)", custom: { initials: "SA", avatar: "#9fa7df" } },
id: "supported-user",
data: { name: "Mary Watson", custom: { initials: "MW", avatar: "#ffab91" } },

When you run the app, you get randomly assigned an ID of one of these two users (support-agent or supported-user). Based on the provided details, the user metadata gets created (createUser()), updated (update()), and retrieved (getUser()) from PubNub's App Context.

const randomizedUsers = Math.random() < 0.5 ? userData : userData.reverse()
const currentUser = await chat.currentUser.update(randomizedUsers[0].data)
const interlocutor =
(await chat.getUser(randomizedUsers[1].id)) ||
(await chat.createUser(randomizedUsers[1].id, randomizedUsers[1].data))

The advantage of having that random logic here is that if you open the app in another browser window and get assigned another user, you can simulate a real-life discussion.

For production apps, you would assign a fixed User ID that becomes the app's current user. User ID identifies your client when communicating with PubNub and is used by PubNub to calculate pricing.

Create channel

Now, you need a channel where these two users can talk and receive messages from each other.

The Chat SDK supports the following channel types:

To simulate a conversation between two users, you'll need a direct channel type.

The ID of the communication channel is hardcoded to Support Channel. When you run the app for the first time, you create the direct (1:1) channel (createDirectConversation()) on the PubNub server.

const { channel } = await chat.createDirectConversation({
user: interlocutor,
channelData: { name: "Support Channel" },

To receive messages from another user, you must be subscribed to the channel, or "connected," as we call it. This guide uses the Chat SDK connect() method to listen for messages, called by the Getting Started app within useEffect() to update its messages state.

useEffect(() => {
if (!channel) return
return channel.connect((message) => setMessages((messages) => [...messages, message]))
}, [channel])

Send messages

The app handles:

  • Incoming messages through the setMessages() function that uses the connect() method to receive messages from another user and then add these messages to the collective message list.
  • Outgoing messages through the handleSend() function that uses the sendText() method to publish messages on the channel.
  useEffect(() => {
if (!channel) return
return channel.connect((message) => setMessages((messages) => [...messages, message]))
}, [channel])


async function handleSend(event: React.SyntheticEvent) {
if (!text || !channel) return
await channel.sendText(text)

The Getting Started app that this guide is based on only supports sending text messages. The Chat SDK, however, also supports files and rich message features like links, @user mentions, or channel references that are similar in logic to @user mentions.

Show time indicator

Another addition to the basic setup is the time indicator in the app. The Chat SDK comes with utility methods handling Unix timestamp to PubNub message timetoken conversion (and vice versa). Our sample chat app converts a message timetoken to a "short" time style, like 08:25.

{TimetokenUtils.timetokenToDate(message.timetoken).toLocaleTimeString([], {
timeStyle: "short",

Add look and feel

The UI for the app is completely customized, and it's up to you to decide what you want your chat to look like. Check the CSS styles used to beautify this sample chat app if interested.


CSS styles

Next steps

You can extend this basic chat app by adding other features, like message reactions, typing indicator, mentions, and many more.

You can also try running another sample and see what a group chat in React Native can look like.

Head to the Features section to explore everything the Chat SDK offers.

Last updated on