# Users

User represents a person who uses a chat and can perform chat operations like viewing channels or sending messages.

## Connecting a User

To perform actions with the SDK, you have to connect a user first. You can use three different types of users: regular, guest, and anonymous users.

### Regular users

Stream uses JWT (JSON Web Tokens) to authenticate regular chat users. These tokens have to be generated by your server and then passed into the client side SDK calls to log in the user.

Note that users will be automatically created when connecting if they don't exist yet.

First, you'll have to create a `User` object:

```kotlin
val user = User(
    id = "bender",
    name = "Bender",
    image = "https://bit.ly/321RmWb",
)
```

Then, you can provide a user token in one of two ways:

1. With a JWT token provided as a string:

   ```kotlin
   val token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoiZmFuY3ktbW9kZS0wIn0.rSnrWOv8EbsiYzJlvVwqwCgATZ1Magj_fZl-bZyCHKI"
   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. Using a `TokenProvider` which will be queried for a token when required:

   ```kotlin
   val tokenProvider = object : TokenProvider {
       // Make a request to your backend to generate a valid token for the user.
       // It is expected that "yourTokenService.getToken" never throws an exception.
       // If the token cannot be loaded, it should return an empty string.
       override fun loadToken(): String = yourTokenService.getToken(user)
   }
   client.connectUser(user, tokenProvider).enqueue { /* ... */ }
   ```

<admonition type="note">

Please ensure that the `TokenProvider.loadToken` implementation never throws an exception.
If the token cannot be loaded, it should return an empty string.

</admonition>

#### Using Development Tokens

For development applications, you can disable token authentication checks in the [Dashboard](https://getstream.io/dashboard). This will let you generate tokens using the `ChatClient` without needing a token provider endpoint.

To disable auth checks, navigate to the [Dashboard](https://getstream.io/dashboard) and complete the following steps:

1. Select your App.
1. Select Chat -> Chat Overview.
1. Scroll to the Authentication section.
1. Toggle _Disable Auth Checks_

Never disable Auth Checks in a production application. Auth checks are an important part of security for a production application and should only be done for proofs-of-concept and applications in the early development stage.

```kotlin
val user = User(
    id = "bender",
    name = "Bender",
    image = "https://bit.ly/321RmWb",
)
val token = ChatClient.devToken(user.id)

ChatClient.connectUser(user, token).enqueue { /* ... */ }
```

#### Manually generating a user token

When you're developing your application, you might want to manually create a valid user token with our [JWT generator](/chat/docs/android/token_generator/).

1. Copy your `API_SECRET` from the [Dashboard](https://getstream.io/dashboard).
1. Open the JWT Generator.
1. Enter your `API_SECRET`, a `User ID`, and set an expiration time.
1. Copy the token generated by the app.

### Guest Users

Guest sessions can be created client-side and do not require any server-side authentication. Support and livestreams are common use cases for guest users because often you want a visitor to be able to use chat in the application without (or before) they have a regular user account.

Guest users are not available to application using multi-tenancy (teams).

<admonition type="note">

Unlike anonymous users, guest users are counted towards your MAU usage.

</admonition>

Guest users have a limited set of permissions. You can create a guest user session by using `connectGuestUser` instead of `connectUser`.

```kotlin
client.connectGuestUser(userId = "bender", username = "Bender").enqueue { /*... */ }
```

### Anonymous Users

If a user is not logged in, you can call the `connectAnonymousUser` method. While you’re anonymous, you can’t do much, but for the `livestream` channel type, you’re still allowed to read the chat conversation.

```kotlin
client.connectAnonymousUser().enqueue { /*... */ }
```

When you connect to chat using anonymously you receive a special user back with the following data:

```xml
{
	"id": "!anon",
	"role": "anonymous",
	"roles": [],
	"created_at": "0001-01-01T00:00:00Z",
	"updated_at": "0001-01-01T00:00:00Z",
	"last_active": "2020-11-02T18:36:01.125136Z",
	"banned": false,
	"online": true,
	"invisible": false,
	"devices": [],
	"mutes": [],
	"channel_mutes": [],
	"unread_count": 0,
	"total_unread_count": 0,
	"unread_channels": 0,
	"language": ""
}
```

<admonition type="note">

Anonymous users are not counted toward your MAU number and only have an impact on the number of concurrent connected clients.

</admonition>

## Querying Users

You can query for existing users using the `ChatClient::queryUsers` method. The example below shows how you can retrieve the details for three specific users by ID in one API call:

```kotlin
// Search for users with id "john", "jack", or "jessie"
val request = QueryUsersRequest(
    filter = Filters.`in`("id", listOf("john", "jack", "jessie")),
    offset = 0,
    limit = 3,
)

client.queryUsers(request).enqueue { result ->
    if (result.isSuccess) {
        val users: List<User> = result.data()
    } else {
        // Handle result.error()
    }
}
```

### Banned users

Another option is to query for banned users. This can be done with the following code snippet:

```kotlin
val request = QueryUsersRequest(
    filter = Filters.eq("banned", true),
    offset = 0,
    limit = 10,
)

client.queryUsers(request).enqueue { /* ... */ }
```

Please be aware that this query will return users banned across the entire app, not at a channel level.

You can filter and sort on the custom fields you've set for your user, the user id, and when the user was last active.

The options for the `queryUsers` method are presence, limit, and offset. If presence is `true` this makes sure you receive the `user.presence.changed` event when a user goes online or offline.

### Users by search term

You can autocomplete the results of your user query by username and/or ID.

If you want to return all users whose username includes `'ro'`, you could do so with the following:

```kotlin
val request = QueryUsersRequest(
    filter = Filters.autocomplete("name", "ro"),
    offset = 0,
    limit = 10,
)
client.queryUsers(request).enqueue { /* ... */ }
```

This would return an array of any matching users, such as:

```kotlin
[
    {
        "id": "userID",
        "name": "Curiosity Rover"
    },
    {
        "id": "userID2",
        "name": "Roxy"
    },
    {
        "id": "userID3",
        "name": "Roxanne"
    }
]
```

## User presence

User presence allows you to show when a user was last active and if they are online right now. Check the following user's properties:

- `online` - a boolean flag that indicates if the user is currently online
- `lastActive` - user's last active date

### Marking a User Invisible

To appear offline to other users, simply set the `invisible` property to `true` when connecting.

```kotlin
val user = User(
    id = "user-id",
    invisible = true,
)
client.connectUser(user, "user-token").enqueue { result ->
    if (result.isSuccess) {
        val user: ConnectionData = result.data()
    } else {
        // Handle result.error()
    }
}
```

<admonition type="note">

User's invisible status can be only set while calling `connectUser` method.

</admonition>

### Listening to User Presence Changes

To listen to changes in user presence, you need to watch some channels or queries first. You can do this in one of three ways:

1. Watch a single channel with `presence = true` set:

   ```kotlin
   val watchRequest = WatchChannelRequest().apply {
       data["members"] = listOf("john", "jack")
       presence = true
   }
   channelClient.watch(watchRequest).enqueue { result ->
       if (result.isSuccess) {
           val channel: Channel = result.data()
       } else {
           // Handle result.error()
       }
   }
   ```

2. Query some channels with `presence = true` set:

   ```kotlin
   val channelsRequest = QueryChannelsRequest(
       filter = Filters.and(
           Filters.eq("type", "messaging"),
           Filters.`in`("members", listOf("john", "jack")),
       ),
       offset = 0,
       limit = 10,
   ).apply {
       presence = true
   }
   client.queryChannels(channelsRequest).enqueue { result ->
       if (result.isSuccess) {
           val channels: List<Channel> = result.data()
       } else {
           // Handle result.error()
       }
   }
   ```

3. Query some users with `presence = true` set:

   ```kotlin
   val usersQuery = QueryUsersRequest(
       filter = Filters.`in`("id", listOf("john", "jack")),
       offset = 0,
       limit = 2,
       presence = true,
   )
   client.queryUsers(usersQuery).enqueue { result ->
       if (result.isSuccess) {
           val users: List<User> = result.data()
       } else {
           // Handle result.error()
       }
   }
   ```

Users' online status change can then be handled by subscribing to the `UserPresenceChangedEvent` event the same you do for any other [event](/chat/docs/sdk/android/v5/client/events/):

```kotlin
// Finally, subscribe to presence to events
client.subscribeFor<UserPresenceChangedEvent> { event ->
    // Handle change
}
```

---

This page was last updated at 2025-08-15T14:15:35.304Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/android/v5/client/users/](https://getstream.io/chat/docs/sdk/android/v5/client/users/).