Chat Docs Introduction

Last Edit: Jan 18 2021

Before reviewing the Chat API docs, we recommend having a look at the tutorials and sample apps.

The interactive API tour is the fastest way to learn how Stream’s Chat API works. Be sure to check that out if you haven’t done so already.


Getting Started

This guide quickly brings you up to speed on Stream’s Chat API. The API is flexible and allows you to build any type of chat or messaging.

You're currently not logged in. Create an account to automatically add your API key and secret to these code examples.

The Stream Chat API client is available as an npm package and also available via yarn.

# using npm
npm install stream-chat

# using yarn
yarn add stream-chat

After installing the package, import the StreamChat module into your project, and you're ready to go:

import { StreamChat } from 'stream-chat';

// or

const StreamChat = require('stream-chat').StreamChat;

The Stream Chat API client is available as a library using Jitpack package repository

Add repository into root build.gradle

allprojects {
  repositories {
    maven { url '' }

Add library dependency into app build.gradle

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8

dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'com.github.GetStream:stream-chat-android-client:latest-version'

The Stream Chat API client is available as a library using Jitpack package repository

Add repository into root build.gradle

allprojects {
  repositories {
    maven { url '' }

Add library dependency into app build.gradle

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8

dependencies {
    implementation 'com.github.GetStream:stream-chat-android-client:latest-version'

You can add Stream Chat to your Xcode project using CocoaPods or with Carthage.


Add this entry in your Podfile and then run pod install

pod 'StreamChatClient', '~> 2.0'


To integrate Stream Chat into your Xcode project using Carthage, specify it in your Cartfile:

github "GetStream/stream-chat-swift"

Then run carthage update --platform iOS --new-resolver and follow these steps:

  • Open your Xcode project

  • Select the project in the Navigator

  • Select your app target

  • Open General panel

  • Click the + button in the Linked Frameworks and Libraries section

  • Click the Add Other... and add StreamChatCore.framework in <Path to your Project>/Carthage/Build/iOS/

  • Add StreamChat.framework

  • Open Build Phases panel

  • Click the + button and select New Run Script Phase

  • Set the content to: /usr/local/bin/carthage copy-frameworks

  • Add to Input Files

    • $(SRCROOT)/Carthage/Build/iOS/StreamChatClient.framework

    • $(SRCROOT)/Carthage/Build/iOS/StreamChatCore.framework

    • $(SRCROOT)/Carthage/Build/iOS/StreamChat.framework

  • Add to Output Files

    • $(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/StreamChatClient.framework

    • $(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/StreamChatCore.framework


The Stream Chat API client is available as public PHP package.

You can install it using composer:

composer require get-stream/stream-chat

After installing the package, include StreamChat into your project, and you're ready to go:

require_once "./vendor/autoload.php";

Chat Client

Let's get started by initializing the client and setting the current user:

const client = new StreamChat("YOUR_API_KEY");
await client.setUser(
        id: 'jlahey',
        name: 'Jim Lahey',
        image: '',

String apiKey = "YOUR_API_KEY";
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiamxhaGV5In0.OkDbpbujWJ-XIVHaf00Dnqt3v8Yp_nQ6CGzm-Z4QUVc";
Context context = getApplicationContext();
ChatClient client = new ChatClient.Builder(apiKey, context).build();

// Set the user to establish the websocket connection
// Usually done when you open the chat interface
// extraData allows you to add any custom fields you want to store about your user
// the UI components will pick up name and image by default

User user = new User("jlahey");

user.getExtraData().put("name", "Jim Lahey");
user.getExtraData().put("image", "");

client.setUser(user, token, new InitConnectionListener() {
    public void onSuccess(@NotNull ConnectionData data) {
        User user = data.getUser();
        String connectionId = data.getConnectionId();

    public void onError(@NotNull ChatError error) {

// Import StreamChatClient framework.
import StreamChatClient

// Setup the Stream Chat Client with your API key 
// Preferably in `application(_ application:didFinishLaunchingWithOptions:)`
// This needs to be called only once, since a singleton cannot be configured multiple times!
// During development we advice to set log to INFO level
Client.configureShared(.init(apiKey: "YOUR_API_KEY", logOptions: .info))

// Create a user, when they login.
let userExtraData = UserExtraData(name: "Jim Lahey", avatarURL: URL(string: "")!)
let user = User(id: "jlahey", extraData: userExtraData)

// Tokens must be generated server-side
// For development, you can use the token generator (see later in the docs)
let token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiamxhaGV5In0.OkDbpbujWJ-XIVHaf00Dnqt3v8Yp_nQ6CGzm-Z4QUVc"

// Setup the current user with its token
// You can also pass a tokenProvider closure
Client.shared.set(user: user, token: token)

val apiKey = "YOUR_API_KEY"
val token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiamxhaGV5In0.OkDbpbujWJ-XIVHaf00Dnqt3v8Yp_nQ6CGzm-Z4QUVc"
val context = getApplicationContext()
val client = ChatClient.Builder(apiKey, context).build()

val user = User("jlahey")
user.extraData["image"] = ""
user.extraData["name"] = "Jim Lahey"

client.setUser(user, token, object : InitConnectionListener() {

    override fun onSuccess(data: ConnectionData) {
        val user = data.user
        val connectionId = data.connectionId

    override fun onError(error: ChatError) {

import 'package:stream_chat/stream_chat.dart';

// create a client with log-level INFO
final client = Client("YOUR_API_KEY", logLevel: Level.INFO);

// init the user object, note how you can specify custom fields as well
final user = User(id: "jlahey", extraData: {
  'name': 'Jim Lahey',
  'image': '',

// sets the current user, from now on the client can be used to query channels and receive events
await client.setUser(user, "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiamxhaGV5In0.OkDbpbujWJ-XIVHaf00Dnqt3v8Yp_nQ6CGzm-Z4QUVc");

$client = new GetStream\StreamChat\Client("STREAM_KEY", "STREAM_API_SECRET");

$bob = [
    'id' => 'bob-1',
    'role' => 'admin',
    'name' => 'Robert Tables',

$bob = $client->updateUser($bob);

The above snippet is for an in-browser or mobile integration. Server-side API calls are a little different, but this is covered in detail later in the documentation.


Let’s continue by initializing your first channel. A channel contains messages, a list of people that are watching the channel, and optionally a list of members (for private conversations). The example below shows how to set up a channel to support chat for a group conversation:

const channel ='messaging', 'travel', {
    name: 'Awesome channel about traveling',

// fetch the channel state, subscribe to future updates
const state = await;

ChannelController channelController =, channelId);
Map<String, Object> extraData = new HashMap<>();

extraData.put("name", "Talking about life");

// watching a channel's state
// note how the withWatch() argument ensures that we are watching the channel for any changes/new messages
ChannelQueryRequest request = new ChannelQueryRequest()

channelController.query(request).enqueue(result -> {

    if (result.isSuccess()) {
        Channel channel =;
    } else {

    return Unit.INSTANCE;

// Create an extra data for a channel.
// ChannelExtraDataCodable is an extension of Codable that makes sure you have common fields 
// used by the UI library (name and imageURL)
struct MyChannelData: ChannelExtraDataCodable {
    var name: String?
    var imageURL: URL?
    let info: String // this is our custom field :)

// Register once your channel extra data type, we'll need it for decoding
Channel.extraDataType = MyChannelData.self

let data = MyChannelData(name: "Travel", imageURL: nil, info: "Awesome channel about traveling")
let channel = .messaging, id: "travel", extraData: data)

// Watching a channel { (result) in
    // handle result

val channelController =, channelId)
val extraData = mutableMapOf<String, Any>()

extraData["name"] = "Talking about life"

// watching a channel"s state
// note how the withWatch() argument ensures that we are watching the channel for any changes/new messages
val request = ChannelQueryRequest()

channelController.query(request).enqueue {
    if (it.isSuccess) {
        val channel =
    } else {

final channel ="messaging", id: "travel", extraData: {
  "name": "Awesome channel about traveling",

// fetch the channel state and subscribe to future updates
final state = await;

// Note: some methods like setUser are not available in server-side clients. 
// Most server-side methods require a <user-id> to be passed as parameter

$channelConf = [ 'name' => 'Awesome channel about traveling' ];

// Instantiate a ‘messaging’ type channel with id ‘travel’
$channel = $client->Channel("messaging", "travel", $channelConf);

// Create the channel  
$state   = $channel->create("bob-1"); // bob-1 is the <user-id> of the creator

The first two arguments are the Channel Type and the Channel ID (messaging and travel in this case). The Channel ID is optional; if you leave it out, the ID is determined based on the list of members. The channel type controls the settings we’re using for this channel.

There are 5 default types of channels:

  • livestream
  • messaging
  • team
  • gaming
  • commerce

These five options above provide you with the most sensible defaults for those use cases. You can also define custom channel types if Stream Chat defaults don’t work for your use-case.

The third argument is an object containing the channel data. You can add as many custom fields as you would like as long as the total size of the object is less than 5KB.


Now that we have the channel set up, let's send our first chat message:

const text = 'I’m mowing the air Rand, I’m mowing the air.';

const response = await channel.sendMessage({
    customField: '123',

// prepare the message
Message message = new Message();
message.setText("hello world");

// send the message to the channel
channelController.sendMessage(message).enqueue(result -> {

    if (result.isSuccess()) {
        Message msg =;
    } else {

    return Unit.INSTANCE;

let channelExtraData = ChannelExtraData(name: "General", imageURL: nil)
let channel = .messaging, id: "general", extraData: channelExtraData)

// Create a message
let message = Message(text: "Hello")

// Send the message
channel.send(message: message) { result in
    do {
        let response = try result.get()
    } catch {
        print("Error when sending message: \(error)")

// prepare the message
val message = Message()
message.text = "hello world"

// send the message to the channel
channel.sendMessage(message).enqueue {
    if (it.isSuccess) {
        val message =
    } else {

final message = Message(
  text: 'I’m mowing the air Rand, I’m mowing the air.',
  extraData: {'customField': '123'},

final response = await channel.sendMessage(message);

$msg_bob = $channel->sendMessage(["text" => "Hello world!"], 'bob-1');

Similar to users and channels, the sendMessage method allows you to add custom fields. When you send a message to a channel, Stream Chat automatically broadcasts to all the people that are watching this channel and updates in real-time.


This is how you can listen to events on the clients-side:

channel.on('', event => {
    console.log('received a new message', event.message.text);
    console.log(`Now have ${channel.state.messages.length} stored in local state`);

// Subscribe
Subscription subscription = -> {

    if (event instanceof NewMessageEvent) {
        Message message = event.message;

    return Unit.INSTANCE;
// Unsubscribe

let channel = .messaging, id: "general")

let subscription = channel.subscribe(forEvents: [.messageNew]) { event in
	// handle new message event

// Cancel subscription when you want to stop receiving events

val subscription = { event ->
    if (event is NewMessageEvent) {
        val message = event.message

channel.on("").listen((Event event) {
  print("received a new message: ${event.message.text}");
You can receive the event and access the full channel state via channel.state.


Now that you understand the building blocks of a fully functional chat integration, let’s move on to the next sections of the documentation, where we dive deeper into details on each API endpoint.