All About Reactions with the Stream Chat Android SDK

Modern chat apps need something to make the messaging platform lively and increase user engagement. Reactions have emerged as a top feature to help in this.

Stream's Chat SDK for Android provides a way for you to add reactions in your application in a matter of minutes.

The SDK has a free trial, and it's free to use for small companies and hobby projects with a Maker Account.

In this tutorial, you're going to learn how to do the following with the low-level Android client library:

  • Add reactions to a message
  • Delete a reaction from a message
  • Use cumulative reactions
  • Paginate reactions

Then, using the Android UI components:

  • Add custom reactions
  • Style the reactions UI

Note: This tutorial assumes you already know the basic knowledge of the Stream API. To get started, check out the Android In-App Messaging Tutorial, and take a look at the Android SDK on GitHub.

Adding a Reaction

Reactions are on most social media apps and there's many of them, for example:

  • Like
  • Favourite/Love
  • Sad/Angry
  • Clap

They're used to represent common, quick reactions that users can have after seeing a piece of content. Using the Stream Chat SDK, you can add reactions to your messages in a very easy way.

You'll find the sample app for this tutorial on GitHub. This is how the app looks:

The app has a TextView which has a Sample message text. It has a favourite ImageButton beside it and a VIEW CHANNEL Button. You'll see the channel functionalities later on in this tutorial.

Tap on the favourite ImageButton. The following BottomSheet modal will appear:

This is the UI for adding your reaction. It has buttons for selecting the reaction type. There are other buttons for adding or reducing the score for your reaction. Once you set everything it should be as follows:

Now that you've seen the UI part, to save your reaction, first, you have to create a Reaction object which has the properties of your reaction.

1val reaction = Reaction(
2        messageId =,
3        type = reactionType,
4        score = score,
5        extraData = mutableMapOf("customField" to 1),

In the code above:

  • You're providing the messageId of the message that you want to react to.
  • You specify the type of the reaction. The type is from the one you selected on the app.
  • Here, you're also adding the score for the reaction. The value for the score is the one you set on the UI.
  • Lastly, you add any arbitrary extra information using extra data.

You have your reaction object ready. Next, you'll be seeing how to send that reaction using the Stream Client.

To send a message reaction, you need a ChannelClient. A ChannelClient enables you to:

  • Create channels
  • Add users to channels
  • Send messages to channels
  • React to messages
  • And a lot more!

On the sample app, you declare the client at the top of the file as:

1private lateinit var channelClient: ChannelClient

It's initialised in your onCreate method as follows:

1channelClient = = "messaging", channelId = "general")

The logic to save a reaction is on the ReactionsBottomSheet. You'll need to pass the sentMesage and channelCient to the class as shown below:

1val modalbottomSheetFragment = ReactionsBottomSheet(channelClient, sentMessage),modalbottomSheetFragment.tag)

Now that you have everything set, to send your reaction object, you need the following code:

1channelClient.sendReaction(reaction).enqueue { result ->
2        if (result.isSuccess) {
3            val sentReaction =
4            reactionViewModel.setMessageId(reaction.messageId)
5            Log.d("Message","Message Reaction score is: ${sentReaction.score}")
6            dismiss()
7        } else {
8            requireContext().toast("Adding reaction Failed")
9        }

Here, you send your reaction object to Stream Client. You're also handling the success and failure states from the callback response. Depending on the result, you handle the states according to your app's needs.

  • If the call succeeds, you call the setMessageId() method in the ViewModel. You pass the id of the reaction which has been saved so that you observe it on your activity.

  • Show a Toast when saving the reactions fails.

When the reaction is saved, you'll see the following image:

Congratulations! You've learned how to add your first message reaction. With Stream's Android SDK, this was simple. Let's see what else you can do with reactions.

Removing a Reaction

To remove a reaction, you only need the messageId and reactionType. The code to remove is as follows:

2        messageId = reaction.messageId,
3        reactionType = reaction.type,
4).enqueue { result ->
5        if (result.isSuccess) {
6            Log.d("Reaction Deleted","Reaction ${reaction.type} has been deleted")
7        } else {
8            showSnackBar("Delete Failed")
9        }

This method is like the one for adding reactions. The difference is that you're calling the deleteReaction method to delete the reaction. You're also passing the messageId and reactionType for the reaction that you want to remove. You're also handling the success and error states.

Cumulative Reactions

Another commonly used reaction is the clap reaction or enabling a user to react more than once. This is useful in blogs and articles. Stream's Android SDK allows this functionality out of the box as well. You do this by specifying the score in your reaction model as shown below:

1val reaction = Reaction(
2    messageId =,
3    type =,
4    score = reactionModel.score,
5    extraData = mutableMapOf("customField" to 1),

Here you specify the score for your reaction. The value for the score is the one from the input on the UI. From here, you can send the reaction in the same way as before:

1channelClient.sendReaction(reaction).enqueue { result -> ... }

When quering reactions with scores, the API will return the sum of all reaction scores as well as each reaction's individual scores. For example, it will tell you that you've received 420 claps in total, and Sam clapped 15 times.

Paginating Reactions

In social apps, a message or a post can get many, many reactions - thousands, at times. In such cases, you can not display all these reactions in your app. To handle this case, the SDK allows you to paginate reactions as you fetch them. In this way, you specify the number that you want to fetch according to the UI of your app.

Here's how an example of to fetch reactions with pagination:

2    messageId = messageId,
3    offset = 0,
4    limit = 10,
5).enqueue { result ->
6    if (result.isSuccess) {
7        val reactions: List<Reaction> =
8        binding.rvReactions.visibility = View.VISIBLE
9        reactionsAdapter.submitList(reactions)
10        binding.rvReactions.adapter = reactionsAdapter
11    } else {
12        showSnackBar("Getting Reactions Failed: ${result.error().message}")
13    }

The getReactions() method takes in three parameters:

  • messageId - ID of the message whose reactions you want to fetch.
  • offset - The position at which you want to start fetching your reactions. This is usually the number of reactions that you've already loaded. For this case, it's 0 since you want to fetch from the first one (so no offset is required).
  • limit - This specifies the number of reactions you want to fetch at a single time. This number can be set based on your UI's needs.

From the sample project, here's how the reactions are:

The API offers a lot of flexibility according to your needs. In the next section you'll be looking and the reactions UI provided by the Stream SDK and how you can customize it.

Reactions with Stream's UI Components

Stream's Android SDK has UI components for reactions built-in. They're useful in case you don't need custom ones as you've been learning in the sections above. This is how they look:

The UI offers a couple of commons reactions for example love, like, and thumbs up. This makes it easy to get started with if you want to use them in your app.

However, at times the requirement for your app can be different. Can I remove the default reactions? Can I add custom reactions? Can I apply my app's style to the reactions? Those are some of the questions you might ask yourself.

And the good news is.... drum rolls 🙂 Yes, you can do all that! You can customize all that in the SDK, and you'll be learning how to do that next.

Customizing the Reactions UI

To customize the reactions, you'll be using the SupportedReactions class, which allows you to define a set of reactions. It accepts two parameters in its constructor:

  • context - App context for loading resources.
  • reactions - This is a Map of keys which hold the reaction type and a ReactionDrawable. This is the parameter you use to add your custom reactions. If you don't provide any reactions, by default it'll use the standard reactions.

A ReactionDrawable is an object that describes the reaction icon. It handles the different states for the icon: it has different drawables for active and inactive states.

To define your own custom reaction, create a ReactionDrawable as follows:

1fun clapDrawable(context: Context): SupportedReactions.ReactionDrawable {
2    val drawableInactive = ContextCompat.getDrawable(context, R.drawable.ic_clapping)!!
3    val drawableActive = ContextCompat.getDrawable(context, R.drawable.ic_clapping)!!.apply {
4        setTint(ContextCompat.getColor(context,android.R.color.holo_red_dark ))
5    }
6    return SupportedReactions.ReactionDrawable(drawableInactive, drawableActive)

This function assembles a ReactionDrawable after loading the drawableInactive and drawableActive icons. The active icon here is a tinted version of the inactive icon.

In the sample project, you can check on the ReactionDrawables.kt file under the utils package for more custom drawables.

Now, you have the drawables ready for use. Next is to create a map of reactions types and their corresponding drawables as follows:

1val reactions: Map<String, SupportedReactions.ReactionDrawable> = mapOf(
2    "like" to likeDrawable(applicationContext),
3    "clap" to clapDrawable(applicationContext),
4    "wondering" to wonderingDrawable(applicationContext),
5    "brilliant" to brilliantDrawable(applicationContext),
6    "handshake" to handShakeDrawable(applicationContext),

Here you have all your custom reactions and their icons. This is all you need. After defining this, the final thing to do is to make sure your app uses the custom reactions that you've created.

You do this by adding this to your initialization code:

1ChatUI.supportedReactions = SupportedReactions(applicationContext, reactions)

Here you're passing your reactions to the Stream's Android SDK. And now this is how your reactions will look like inside the UI components:

Woohoo! As you can now see, all the reactions are custom ones and with different colors!.

In the next section, you'll see how to customize the colors of the reaction card.

Adding your Custom Styling to Reactions

At times you need the UI for the reactions to adapt to the styling of your app. Stream's Android SDK also supports this in a simple and straightforward way. For the title text, you can add the following in your themes.xml file:

1<item name="streamUiUserReactionsTitleTextColor">@color/white</item>
2<item name="streamUiUserReactionsTitleTextSize">18sp</item>
3<item name="streamUiUserReactionsTitleTextFont">@font/benton_sans_book</item>
4<item name="streamUiUserReactionsTitleTextStyle">italic</item>
5<item name="streamUiUserReactionsBackgroundColor">@color/purple_200</item>

From the above attributes you can see you that you're able to change:

  • Color
  • Text Size
  • Font
  • Style
  • Card Background.

This is how the final results look like with the above settings:

Albeit yours will be different depending on your app colors and styling requirements.


You've learned how to add, remove, paginate and add cumulative reactions in this tutorial. In the process, you've also learned how you can create your custom reactions, including integrating them with Stream's UI Components. You've also seen how to customize reactions in the Stream SDK, and also add your custom reactions.

To learn more about Stream's Android SDK, go to the GitHub repository which is a great starting point to all the available docs and samples.

You can get the full sample project with the examples shown in this tutorial here.