// Typically done in your Application class using your API Key on startup
val client = ChatClient.Builder("{{ api_key }}", context).build()
// Static reference to initialised client
val staticClientRef = ChatClient.instance()
Initialization & Users
The code below creates a chat client instance for interacting with Stream APIs. Additional options, such as API base URL, can be configured when creating the instance.
import { StreamChat } from 'stream-chat';
// client-side you initialize the Chat client with your API key
const chatClient = StreamChat.getInstance('{{ api_key }}', {
timeout: 6000,
});
// API key can be found on the dashboard: https://getstream.io/dashboard/
let config = ChatClientConfig(apiKey: .init("<# Your API Key Here #>"))
// Create an instance of ChatClient
let chatClient = ChatClient(config: config)
// Recommendation is to store it as a shared instance
extension ChatClient {
static var shared: ChatClient!
}
ChatClient.shared = chatClient
// client-side you initialize the Chat client with your API key
final client = StreamChatClient(
"{{ api_key }}",
logLevel: Level.INFO,
connectTimeout: Duration(milliseconds: 6000),
receiveTimeout: Duration(milliseconds: 6000),
);
Client = CreateDefaultSubobject<UStreamChatClientComponent>(TEXT("Client"));
Client->ApiKey = TEXT("{{ api_key }}");
// Typically done in your Application class on startup
ChatClient client = new ChatClient.Builder("{{ api_key }}", context).build();
// Client singleton is also available via static reference
ChatClient staticClientRef = ChatClient.instance();
var client = StreamChatClient.CreateDefaultClient();
Connecting the User
Once initialized, you must specify the current user with connectUser
:
val user = User(
id = "bender",
extraData = mutableMapOf(
"name" to "Bender",
"image" to "https://bit.ly/321RmWb",
),
)
// You can setup a user token in two ways:
// 1. Setup the current user with a JWT token
val token = "{{ chat_user_token }}"
client.connectUser(user, token).enqueue { result ->
if (result.isSuccess) {
// Logged in
val user: User = result.data().user
val connectionId: String = result.data().connectionId
} else {
// Handle result.error()
}
}
// 2. Setup the current user with a TokenProvider
val tokenProvider = object : TokenProvider {
// Make a request to your backend to generate a valid token for the user
override fun loadToken(): String = yourTokenService.getToken(user)
}
client.connectUser(user, tokenProvider).enqueue { /* ... */ }
await chatClient.connectUser(
{
id: 'john',
name: 'John Doe',
image: 'https://getstream.io/random_svg/?name=John',
},
'{{ chat_user_token }}',
);
// Option A: with expiring token
// The `tokenProvider` closure will be called again when the token is expired
ChatClient.shared.connectUser(
userInfo: .init(id: userID),
tokenProvider: { providerResult in
loadChatToken(completion: providerResult)
},
completion: { error in
if let error = error {
print("Connection failed with: \(error)")
} else {
// User successfully connected
}
}
)
// or alternatively, using the async-await method
let connectedUser = try await ChatClient.shared.connectUser(
userInfo: .init(id: userID),
tokenProvider: { providerResult in
loadChatToken(completion: providerResult)
}
)
// An example of a token provider
func loadChatToken(completion: @escaping (Result<Token, Error>) -> Void) {
NetworkingLayer.getChatToken() { token in
do {
let token = try Token(rawValue: token)
completion(.success(token))
} catch {
completion(.failure(error))
}
}
}
// Option B: with a non-expiring token
// You can generate the token for this user from https://getstream.io/chat/docs/ios-swift/token_generator/?language=swift
let token: Token = "{{ chat_user_token }}"
/// Connect the user using a closure based method
ChatClient.shared.connectUser(
userInfo: .init(id: userID),
token: token
) { error in
if let error = error {
print("Connection failed with: \(error)")
} else {
// User successfully connected
}
}
// or alternatively, using the async-await method
let connectedUser = try await ChatClient.shared.connectUser(
userInfo: .init(id: userID),
token: token
)
final user = User(id: "john", extraData: {
"name": "John Doe",
"image": "https://i.imgur.com/fR9Jz14.png",
});
await client.connectUser(user, "{{ chat_user_token }}");
const FUser User{TEXT("john")};
const FString Token{TEXT("{{ chat_user_token }}")};
Client->ConnectUser(
User,
Token,
[](const FOwnUser& UserRef)
{
// Connection established
});
User user = new User();
user.setId("bender");
user.setName("Bender");
user.setImage("https://bit.ly/321RmWb");
// You can setup a user token in two ways:
// 1. Setup the current user with a JWT token
String token = "{{ chat_user_token }}";
client.connectUser(user, token).enqueue(result -> {
if (result.isSuccess()) {
// Logged in
User userRes = result.data().getUser();
String connectionId = result.data().getConnectionId();
} else {
// Handle result.error()
}
});
// 2. Setup the current user with a TokenProvider
TokenProvider tokenProvider = new TokenProvider() {
@NotNull
@Override
public String loadToken() {
return yourTokenService.getToken(user);
}
};
client.connectUser(user, tokenProvider).enqueue(result -> {/* ... */});
var localUserData = await client.ConnectUserAsync("api_key", "chat_user", "chat_user_token");
// After await is complete the user is connected
// Alternatively, you subscribe to the IStreamChatClient.Connected event
client.Connected += localUserData =>
{
// User is connected
};
Note how we are waiting for the connectUser
API call to be completed before moving forward. You should always make sure to have the user set before making any more calls. All SDKs make this very easy and wait or queue requests until then.
Connect User Parameters
name | type | description | default | optional |
---|---|---|---|---|
user | object | The user object. Must have an id field. User Ids can only contain characters a-z, 0-9, and special characters @ _ and - It can have as many custom fields as you want, as long as the total size of the object is less than 5KB | ||
userToken | string | The user authentication token. See Tokens & Authentication for details | default |
WebSocket Connections
The connectUser
(or SDK equivalent) function performs several operations when used. Please note that this method should never be used server-side.
Creates a new user if the
user_id
is not already registered with the application, incrementing the monthly active usersUpdates the user in the application (will add/modify existing fields but will not overwrite/delete previously set fields unless the key is used)
Opens a WebSocket connection and increments the Concurrent Connections for the application
The React-native, iOS, Android, and Flutter SDK’s handle WebSocket disconnection logic, but if a manual disconnect is required in your application, then there are the following options
ChatClient.instance().disconnect(flushPersistence = false).enqueue { /* ... */ }
await chatClient.disconnectUser();
chatClient.disconnect {
// disconnected
}
// or
await chatClient.disconnect()
await client.disconnectUser();
Client->DisconnectUser();
ChatClient.instance().disconnect(true).enqueue();
await client.DisconnectUserAsync();
XHR Fallback
Most browsers support WebSocket connections as an efficient mode of real-time data transfer. However, sometimes the connection cannot be established due to network or a corporate firewall. In such cases, the client will establish or switch to XHR fallback mechanisms and gently poll our service to keep the client up-to-date.
The fallback mechanism can be enabled with the flag enableWSFallback
const chatClient = StreamChat.getInstance(‘apiKey’, { enableWSFallBack: true });
Privacy Settings
Additionally, when connecting the user, you can include the privacy_settings
as part of the user object.
await chatClient.connectUser(
{
id: 'john',
name: 'John Doe',
image: 'https://getstream.io/random_svg/?name=John',
privacy_settings: {
typing_indicators: {
enabled: false
},
read_receipts: {
enabled: false
}
}
},
'{{ chat_user_token }}',
);
// Connect the user using a closure based method
chatClient.connectUser(
userInfo: .init(
id: userID,
privacySettings: .init(
typingIndicators: .init(enabled: true),
readReceipts: .init(enabled: true)
)
),
token: token
) { error in
// …
}
// or alternatively, using the async-await method
let connectedUser = try await chatClient.connectUser(
userInfo: .init(
id: userID,
privacySettings: .init(
typingIndicators: .init(enabled: true),
readReceipts: .init(enabled: true)
)
),
token: token
)
Let’s have a closer look on the parameters:
name | type | description | default | optional |
---|---|---|---|---|
typing_indicators | object | if enabled is set to false, then typing.start and typing.stop events will be ignored for this user and these events will not be sent to others | enabled: true | ✓ |
read_receipts | object | If enabled is set to false, then the read_state of this user will not be exposed to others. Additionally, read_state related events will not be delivered to others when this user reads messages. | enabled: true | ✓ |