14 October 2022
Developing Amazon Chime chat – a project case study
A text chat – you’d think that something as familiar as this would be easy to implement. And most of the time, it is. But in a recent project of mine, my team and I ran into unexpected challenges when adding a text chat feature using the Amazon Chime SDK. Dive with me into the case study and find out what custom solutions allowed us to get past an API request throttling scare, scalability issues, and other challenges.
Did you know that text chat is one of the oldest applications of the internet as we know it today?
Doug Brown and David R. Woolley implemented the Talkomatic text chat back in 1973 on the famous PLATO system, associated with the invention of many other concepts essential to the modern-day online world, including but not limited to
- message boards,
- chat rooms,
- remote screen sharing
And here we are in 2022 being challenged by a text chat! But to the defense of my team and me, this particular text chat was really a handful.
Let’s talk a bit about the project at hand to find out why.
One of our clients is a major event service company. It operates a platform that sells tickets to a great variety of happenings – concerts, sporting events, spectacles, and so on. The client provides infrastructure for ticket validation at venue gates.
The COVID-19 pandemic had a profound impact on a business model of a company like this. The management accepted a challenge and came up with the idea of offering online events. The artists could perform remotely and even interact with their fans using various features, designed to make up for a lack of ability to connect with fans the way it is only possible during onsite events.
The client managed to create a WordPress-based proof of concept platform and validate the business idea successfully.
However, in order to achieve optimal performance and long-term scalability, they needed a more custom solution. That’s when they reached out to The Software House.
Challenge – to build a chat app for an event streaming platform
The platform was designed to make it as easy as possible to stream an event for both organizers and fans.
The functionality responsible for setting up a new event is most relevant for organizers. It consisted of a number of easy-to-complete forms. Once filled in, the system would generate an event landing page for the fans to enter.
The landing page itself includes a number of features:
- A ticket gateway that includes a form the client fills in by typing their ticket code.
- A WebSocket-based security feature that makes sure that only one device is logged in for each ticket code.
- An emoji functionality designed as an easy way for fans to express their emotions during the live event.
- A text chat for the artist and fans to interact. The solution is based on Amazon Chime.
The first three elements did not pose any particular challenges. That’s why going forward, I will focus on that pesky text chat. What was the problem with that?
In order to understand this, let’s go over the technical and business requirements of the chat.
The chat app had a couple of technical quirks compared to a typical app of this kind due to the way it relied on actual physical tickets sold for a particular event:
- For starters, all participants of chat-enabled events should be able to access the chat feature.
- The chat becomes accessible immediately after the user types in the ticket code. There is no need for registration because the account is created automatically beforehand, following the purchase of a ticket.
- All chat resources should be created prior to the event.
- Due to throttling issues (read our API throttling case study of the same project to learn more), resource creation should not be directly connected to ticket data retrieval. Instead, we should create a separate service that handles it.
- Chat resource creation needs to be monitored to ensure that throttling limits set by Amazon Chime are met. Most unused resources, such as users and channels assigned to an event, are to be deleted as soon as possible. The exception is the history of messages, which is to be archived. User accounts are single-use and removed after an event because the ticket does not have any information about user accounts. As such, it’s not possible to associate a user with an existing account based on ticket data.
There were also some essential requirements expressed by the business:
- Providing the artist and their fans with the ability to interact.
- Equipping chat admins with the ability to moderate chat conversations to prevent spam and other undesirable content.
- All URLs made available in the chat should be displayed in plain text as a safety measure against a variety of bad actors that may link to dangerous pages.
- Upcoming events should be prioritized when it comes to creating chat resources. That’s to ensure that clients who bought their tickets on the day of the event are accounted for.
- Each chat user can pick a unique nickname.
Now, why is Amazon Chime the best tool to implement this functionality?
Solution – Amazon Chime comes out on top
The Amazon Chime communications service wasn’t the only solution we considered, but it eventually emerged as a clear favorite. Let me elaborate on that for a while.
Why did we go for Chime?
The truth is that neither I nor any of my team members were very experienced with Chime. After all, Amazon made its public API available just 6 months before the start of the project. However, we have all been using the AWS infrastructure for a long time, even for various aspects of the system at hand. As a result, we didn’t have to create any new accounts to incorporate Chime into the project. What’s more, you can combine the costs with other AWS payments into a single bill.
As an alternative to that approach, we considered developing a chat using pure WebSockets combined with a library such as ws or socket.io. At the end of the day, the convenience of using Amazon Chime proved decisive. Compared to our own WebSocket server, with Chime, we don’t have to worry about server scalability. All that remains is to make sure that we do not exceed API request and resource creation limits. In this place, it’s worth it to mention that AWS also provides you with a React-based Chime library full of ready-made components that makes working with Chime even easier. However, for our implementation, we chose to build our own components.
There’s also one more reason why Chime emerged as a contender early. Initially, the client planned to include a teleconferencing feature as well. Though we eventually scrapped this idea, you can definitely do that with Chime too!
What can Chime do?
And that brings me to another issue – the full capabilities of Chime. We didn’t use everything Amazon Chime offers in this project, but the potential itself attracted us to this solution.
First of all, you can use Amazon Chime for a text meeting chat in many ways. We have used the SDK to create our own custom chat to conduct online meetings, but you can also try a ready-made Chime system for online meetings, chatting, and placing business calls. This could work really well as an internal tool in your organization. To that end, it really is an easy to use application. Download Chime and check it out for yourself.
What’s more, you can use the SDK to develop other solutions, the most important one being the aforementioned teleconferencing feature (video conferencing). With a little bit of work, you can most definitely develop something similar to Zoom or Google Meet to make video calls (including on mobile devices), phone calls with high quality audio, join meetings, stay connected etc.
These are some of the key features of Amazon Chime.
Chime under the microscope
In order to better understand how developing the chat with Amazon Chime SDK works, it’s worth it to talk about the types of resources it uses. Combined, these resources allow you to bring the chat to full readiness. I’m going to reference these resources later on in the implementation section:
- App Instance – basic Chime chat management resource type. It’s a container other resources are assigned to.
- App Instance Admin – a special user with the ability to modify other Chime resources (in particular channel management).
- Channel – a chat room that groups a number of users.
- User – any chat participant.
- Channel Moderator – a user that has special privileges to act as a moderator.
- Channel Membership – an association between the user and the channel. Without this resource, the user can’t access a channel.
With that said, we can move on to the implementation itself!
Amazon Chime chat implementation
Let’s take this chat app step by step! Keep in mind that the code examples use mock data and combine bits and pieces of different examples. They should not be applied without any changes to other projects.
Text chat app with Amazon Chime implementation
First, we need to create some essential chat resources, such as channels or users.
We start by creating an app instance. We give it a name and assign it a user with the role of an admin. It’s essential to do these steps before we start using the chat functionality. In addition to that, ARN (Amazon Resource Names) identifiers of the app instance and admin should be stored in the database for use in the next steps.
Now we can start the actual implementation of the text chat, starting with creating a channel as well as a dedicated moderator.
As you can see, we used the same method (createAppInstanceUser) to create both an App Instance Admin user and a channel moderator user. It’s the correct way to do it. After all, all users are essentially the same. You can assign them privileges using special functions such as createChannelModerator or createAppInstanceAdmin.
Now we’re going to use the same method for one final time in order to create the account of a regular user. We’re going to assign them to a channel at the same time.
Done! The channel and user are ready to go. Now, we’re going to provide the user with the ability to log in to the channel.
The frontend chat client implementation requires AWS STS credentials to be used during the logging process. We obtain them by providing the IAM role we want to use. The IAM role refers to privileges you can assign to an AWS cloud resource.
The text chat uses two roles – a moderator and a regular user. We’re going to review their privileges.
For the moderator:
As for the regular user:
The logging process makes use of the ARN identifiers of both user roles. For security reasons, the process of getting credentials and the chat logging URL should take place on the server side.
We’re going to implement the following backend code to get the user to log in to the channel:
The information returned by the backend will be used for both logging in and further communication.
Logging on the frontend
Quite a lot is going on here! Let’s break it down:
- The first step is to get logging information and/or credentials from the backend.
- Then, we can create a Chime Messaging client using the aws-sdk package methods. It requires us to provide the STS credentials we obtained before (access key, secret access key, session token) as well as information on the region we operate from.
- Then, we configure a session, providing information on the users, Chime logging endpoint, and client as well as a reference to the AWS SDK library and logger.
- We add all the functions related to Chime events to the MessagingSessionObserver object.
- We start the session and the chat is now functional!
The logging script is largely based on the session creation instruction for the Amazon Chime video conferencing tool. This documentation also has a list of all the other Chime communication methods made available by Amazon Chime SDK.
Making the chat accessible to the user
The user can now log in to the channel. It would be even better if they could also do something once they are there. For starters, they should be able to see a list of all messages sent to the channel by other users before they joined.
In order to retrieve all past messages, the NextToken value should be used and updated for each subsequent call. AWS limits mean that we can retrieve up to 50 messages at a time.
The chat history is now fully functional. We’re going to become a part of it by generating a message!
Simple, isn’t it? The MessageType enum allows us to make a distinction between messages sent by regular users and actions taken by moderators (e.g. removing offensive messages). The content of a message is a JSON file parsed to a string. The file’s structure is as defined in the code above.
How about receiving messages from others? We can use the aforementioned observer to make it happen:
The message.type values come from the Chime library and make it easier to tell what kind of event caused a given callback.
The payload we parse to JSON is the structure in which we send the information needed to find out how a given message should be parsed. There are many different potential actions to be taken:
- Should it be sent to the user?
- Should the previous message be hidden?
- Should the banned user be removed from the chat altogether?
It all depends on how the chat is designed and how many of the available methods are used.
For example, If we wanted to use a moderation function to ban a user and hide their message, we could do the following:
Difficulties during implementation
As you can see, it took quite a few tweaks to make this chat app work. That’s to be expected from tailor-made solutions. Let’s go over the most noteworthy challenges my team and I came across.
I already wrote more about the issue of throttling in my previous AWS API throttling article about this project. As a result of the Chime configuration, my team struggled to get around the limit of 10 requests per second. To combat this issue, a separate EC2 instance was set up to create Chime resources asynchronously.
This brings us to another important point – the importance of proper resource management. There was no count function and the app could only take in 50 requests at a time. It proved a problem when handling instances that had as many as 100,000 users. We were able to find a way around it by creating new entries in a local Node.js app database.
On the bright side, the removal of resources was not a problem – all the messages, user associations, and so on are deleted automatically when you delete a channel. Naturally, the channel users remain as they are not tied to a specific channel and can join multiple ones at the same time.
Each instance launched its own cron job to create resources, which caused the problem of duplicates. The solution to throttling, that is creating a single Chime management instance, dealt with this problem as well.
No AWS console is available for the SDK version
Unfortunately, you can’t use an AWS console for keeping track of all the resources. A console like this does exist, but it’s only available for the AWS-hosted version of Amazon Chime.
At the time of working on the app, the Amazon Chime documentation was quite lackluster. It was being developed and improved upon alongside the actual app. As a result, my team and I learned some of the intricacies of Chime the hard way. To their credit, AWS greatly improved the docs ever since.
Do you want to read more about our best implementations? Check out these case studies.
Despite quite a few obstacles, the project proved very successful at the end of the day. After all, we delivered all that was required from both the perspective of technology and business.
- We created a fully functional custom Chime-based chat app.
- To circumvent the limitations of technology, we provided a separate service for chat resource management.
- We also delivered an interactive presentation that goes over all details of the presentation for the client.
- The artists and users are provided with a way to interact during a streamed event in a way that was envisioned by the business.
- Archived message history is made available for the client in case someone used the chat in an illegal manner.
To express it in numbers:
Lessons learned & conclusions
If you made it all the way here, you must be considering using Amazon Chime or building a similar text chat. I’ll leave you with a couple of final thoughts that will spare you a lot of headaches.
- Separation of concerns is a great way of guarding your app against all sorts of situations in which your services are suddenly blocked. The first version of the app created events and chat resources simultaneously, causing AWS to block the stream altogether. In the final version, in the rare event, the chat doesn’t work, users will still be able to access the stream.
- Server capacity is key, regardless of what tool you use. Even if you self-host everything and there are no hard-set limits, you might still cause your infrastructure to crash due to overwhelming traffic.
- Amazon Chime is a powerful tool, but it still has ways to go. It could definitely use more methods capable of operating on more than one resource. The documentation needs some work as well.
Do you like Amazon Chime? Are you considering it for your next project?
Consult it with our team, which has experienced Amazon Chime first-hand!