// 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 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 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_idis 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.
val user = User( id = "bender", extraData = mutableMapOf( "name" to "Bender", "image" to "https://bit.ly/321RmWb", ), privacySettings = PrivacySettings( typingIndicators = TypingIndicators( enabled = false, ), readReceipts = ReadReceipts( enabled = false, ) ) ) client.connectUser(user, token).enqueue { /* ... */ }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 | ✓ |