The code below creates a chat client instance for interacting with Stream APIs. A singleton client instance means the Chat client is created once and reused throughout your app, ensuring consistent state, avoiding duplicate connections, and simplifying resource management.
// Typically done in your Application class using your API Key on startupval client = ChatClient.Builder("{{ api_key }}", context).build()// Static reference to initialised clientval staticClientRef = ChatClient.instance()
import { StreamChat } from "stream-chat";// client-side you initialize the Chat client with your API keyconst 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 ChatClientlet chatClient = ChatClient(config: config)// Recommendation is to store it as a shared instanceextension ChatClient { static var shared: ChatClient!}ChatClient.shared = chatClient
// client-side you initialize the Chat client with your API keyfinal client = StreamChatClient( "{{ api_key }}", logLevel: Level.INFO, connectTimeout: Duration(milliseconds: 6000), receiveTimeout: Duration(milliseconds: 6000),);
// Typically done in your Application class on startupChatClient client = new ChatClient.Builder("{{ api_key }}", context).build();// Client singleton is also available via static referenceChatClient staticClientRef = ChatClient.instance();
var client = StreamChatClient.CreateDefaultClient();
Once the client is initialized, your app authenticates the user and establishes a Websocket connection by calling connectUser. This function uses your token provider function to request a token from your server.
The connectUser function acts as an upsert for the user object and is a primary method for creating users client-side.
Before attempting subsequent API requests to Stream, it is important that the connectUser function fully resolves.
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 tokenval token = "{{ chat_user_token }}"client.connectUser(user, token).enqueue { result -> if (result is Result.Success) { // Logged in val user: User = result.value.user val connectionId: String = result.value.connectionId } else { // Handle Result.Failure }}// 2. Setup the current user with a TokenProviderval tokenProvider = object : TokenProvider { // Make a request to your backend to generate a valid token for the user. // loadToken() is called on the initial connection and again when a fresh // token is needed (token expiry, auth error, or a reconnection that cannot // reuse the cached token), so keep this implementation resilient to a // missing or slow network. override fun loadToken(): String = yourTokenService.getToken(user)}client.connectUser(user, tokenProvider).enqueue { /* ... */ }
// Option A: with expiring token// The `tokenProvider` closure will be called again when the token is expiredChatClient.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 methodlet connectedUser = try await ChatClient.shared.connectUser( userInfo: .init(id: userID), tokenProvider: { providerResult in loadChatToken(completion: providerResult) })// An example of a token providerfunc 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/tokens_and_authentication/?language=swiftlet token: Token = "{{ chat_user_token }}"/// Connect the user using a closure based methodChatClient.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 methodlet 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 }}");
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 tokenString 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 TokenProviderTokenProvider tokenProvider = new TokenProvider() { @NotNull @Override public String loadToken() { // loadToken() is called on the initial connection and again when a fresh // token is needed (token expiry, auth error, or a reconnection that cannot // reuse the cached token), so keep this implementation resilient to a // missing or slow network. return yourTokenService.getToken(user); }};client.connectUser(user, tokenProvider).enqueue(result -> {/* ... */});
// 1. Static JWT token - prototyping/tests only. In production, issue tokens// from your backend.var localUserData = await client.ConnectUserAsync("api_key", "chat_user", "chat_user_token");// Await returns once connected; you can also subscribe to client.Connected.client.Connected += connectedUser => { /* User is connected */ };// 2. Production: implement ITokenProvider. The SDK calls GetTokenAsync on// initial connect, reconnect, and expiration, so the WebSocket stays// connected across token refreshes automatically.var tokenProvider = new YourTokenProvider();await client.ConnectUserAsync("api_key", "chat_user", tokenProvider);// Your backend MUST authenticate the caller before issuing a Stream token -// never expose an endpoint that returns a token for any userId.public class YourTokenProvider : ITokenProvider{ public Task<string> GetTokenAsync(string userId) => Task.FromResult("token-fetched-from-your-backend");}
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/function
The Token Provider function or authentication token. See Tokens & Authentication for details
default
On Android, the SDK manages the WebSocket connection across the app lifecycle and calls your TokenProvider again when a fresh token is needed (token expiry, an authentication error, or a reconnection that cannot reuse the cached token). For the full lifecycle behavior, manual disconnect and reconnect, and how to handle token fetch failures in the background, see Handling User Connection.
The client-side SDKs handle WebSocket disconnection logic, but if a manual disconnect is required in your application, there are the following options:
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
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.