# Initialization & Users

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.

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
// 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()
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
import { StreamChat } from "stream-chat";

// client-side you initialize the Chat client with your API key
const chatClient = StreamChat.getInstance("{{ api_key }}", {
  timeout: 6000,
});
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// 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
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
// 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),
);
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
Client = CreateDefaultSubobject<UStreamChatClientComponent>(TEXT("Client"));
Client->ApiKey = TEXT("{{ api_key }}");
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
// 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();
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
var client = StreamChatClient.CreateDefaultClient();
```

</codetabs-item>

</codetabs>

## Connecting Users

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.

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
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 { /* ... */ }
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
await chatClient.connectUser(
  {
    id: "john",
    name: "John Doe",
    image: "https://getstream.io/random_svg/?name=John",
  },
  tokenProvider,
);
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// 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/tokens_and_authentication/?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
)
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
final user = User(id: "john", extraData: {
 "name": "John Doe",
 "image": "https://i.imgur.com/fR9Jz14.png",
});

await client.connectUser(user, "{{ chat_user_token }}");
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
const FUser User{TEXT("john")};
const FString Token{TEXT("{{ chat_user_token }}")};
Client->ConnectUser(
  User,
  Token,
  [](const FOwnUser& UserRef)
  {
    // Connection established
  });
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
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 -> {/* ... */});
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
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
};
```

</codetabs-item>

</codetabs>

### 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/function | The Token Provider function or authentication token. See [Tokens & Authentication](/chat/docs/<framework>/tokens_and_authentication/) for details                                                                                    | default |          |

## Disconnecting Users

The client-side SDKs handle WebSocket disconnection logic, but if a manual disconnect is required in your application, there are the following options:

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin
ChatClient.instance().disconnect(flushPersistence = false).enqueue { /* ... */ }
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
await chatClient.disconnectUser();
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
chatClient.disconnect {
  // disconnected
}
// or
await chatClient.disconnect()
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
await client.disconnectUser();
```

</codetabs-item>

<codetabs-item value="unreal" label="Unreal">

```cpp
Client->DisconnectUser();
```

</codetabs-item>

<codetabs-item value="java" label="Java">

```java
ChatClient.instance().disconnect(true).enqueue();
```

</codetabs-item>

<codetabs-item value="unity" label="Unity">

```csharp
await client.DisconnectUserAsync();
```

</codetabs-item>

</codetabs>

## 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`

<codetabs>

<codetabs-item value="javascript" label="JavaScript">

```js
const chatClient = StreamChat.getInstance(‘apiKey’, { enableWSFallBack: true });
```

</codetabs-item>

</codetabs>

## Privacy Settings

Additionally, when connecting the user, you can include the `privacy_settings` as part of the user object.

<codetabs>

<codetabs-item value="kotlin" label="Kotlin">

```kotlin { 7-14 }
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 { /* ... */ }
```

</codetabs-item>

<codetabs-item value="javascript" label="JavaScript">

```js
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 }}",
);
```

</codetabs-item>

<codetabs-item value="swift" label="Swift">

```swift
// 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
)
```

</codetabs-item>

<codetabs-item value="dart" label="Dart">

```dart
final user = OwnUser(
  id: "john",
  extraData: {
    "name": "John Doe",
    "image": "https://i.imgur.com/fR9Jz14.png",
  },
  privacySettings: PrivacySettings(
    typingIndicators: TypingIndicators(
      enabled: false,
    ),
    readReceipts: ReadReceipts(
      enabled: false,
    ),
  ),
);

await client.connectUser(user, "{{ chat_user_token }}");
```

</codetabs-item>

</codetabs>

| 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 | ✓        |


---

This page was last updated at 2026-03-05T19:05:46.816Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/node/init_and_users/](https://getstream.io/chat/docs/node/init_and_users/).