This is documentation for Stream Chat Android SDK v5, which is nolonger actively maintained. For up-to-date documentation, see the latest version (v6).

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:

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:

    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:

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

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

Using Development Tokens

For development applications, you can disable token authentication checks in the Dashboard. This will let you generate tokens using the ChatClient without needing a token provider endpoint.

To disable auth checks, navigate to the Dashboard and complete the following steps:

  1. Select your App.
  2. Select Chat -> Chat Overview.
  3. Scroll to the Authentication section.
  4. 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.

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.

  1. Copy your API_SECRET from the Dashboard.
  2. Open the JWT Generator.
  3. Enter your API_SECRET, a User ID, and set an expiration time.
  4. 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).

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

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

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.

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

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

{
	"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": ""
}

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

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:

// 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:

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:

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:

[
    {
        "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.

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()
    }
}

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

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:

    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:

    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:

    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:

// Finally, subscribe to presence to events
client.subscribeFor<UserPresenceChangedEvent> { event ->
    // Handle change
}
© Getstream.io, Inc. All Rights Reserved.