Auction App Demo with Amazon Interactive Video Service Chat and ReactJS
We have introduced Amazon Interactive Video Service (IVS) Chat in our previous blog post. This post will now showcase a project that demonstrates how to run and integrate IVS Chat using ReactJS.
This is the finished Project:
In this article, you’ll learn about
- How to use the AWS Console to create chat rooms
- How to use amazon-ivs-chat-messaging API
- How to use AWS SDK for IVS Chat
So what is so great about IVS Chat?
Loads! Amazon Interactive Video Service Chat (IVS Chat) offers several compelling features and benefits, making it a powerful tool for developers looking to add real-time messaging capabilities to their applications. Here are some key aspects:
1. Real-Time Interaction that Drives Engagement
IVS Chat allows viewers to interact with the content creator and other viewers in real-time. This immediacy creates a sense of community and engagement that is often missing in traditional video streaming.
2. Customizable Moderation Tools
To ensure a safe and positive environment, IVS Chat provides customizable moderation tools. This helps in managing the conversation, filtering out inappropriate content, and maintaining a respectful community.
3. Scalability
IVS Chat can handle large volumes of simultaneous users, making it suitable for events with a large audience. This scalability ensures that the chat remains functional and responsive, even during peak traffic.
4. Analytics and Insights
The service often includes analytics tools, providing valuable insights into viewer behavior and preferences. This data can be used to improve content and tailor it more effectively to the audience.
5. Customization and Branding
IVS Chat allows for customization of appearance and functionality, enabling content creators to tailor the chat experience to their brand and audience’s needs.
How is IVS chat used for auction?
A Streamer can create a chat room while streaming, and Viewers who are watching the stream enter the chat room and send messages. All viewers of the stream receive the messages sent by other viewers.
If we apply this to an auction app for bidding, it will look like this.
chat room => Bidding room
chat comment => A Bid
Streamer => Auctioneer
Viewers => Bidders
We can use the Chat functionality to bid, and whomever is in the same auction will be able to receive the updated bids (chat messages).
Steps to create a bidding system using chat:
- Create a ChatToken
- Create an auction form
- Start bid (Streamer)
- Receive start bid (Viewer)
- Send bid (Viewer)
- Receive bid message (Streamer and Viewer)
- End auction
- Receive end auction and show bid results
1. Create a ChatToken
First, we made it so that whenever the pages /streamer or /viewers is accessed, a chat room Token is created.
When a chat room Token is created successfully, that means the viewer has entered a chat room, and is ready to send messages!
useChatTokenSetup.js
import { useEffect, useState } from 'react'
import { ChatRoom } from 'amazon-ivs-chat-messaging'
const getChatToken = async (username) => {
const result = await fetch('/api/chatToken', {
method: 'POST',
body: JSON.stringify({ username })
})
const chatTokenInfo = await result.json()
if (!chatTokenInfo) return null
chatTokenInfo.sessionExpirationTime = new Date(chatTokenInfo.sessionExpirationTime)
chatTokenInfo.tokenExpirationTime = new Date(chatTokenInfo.tokenExpirationTime)
return chatTokenInfo
}
export const useChatTokenSetup = (username) => {
const [room, setRoom] = useState(null)
useEffect(() => {
if (!username) return
const chatRoom = new ChatRoom({
regionOrUrl: process.env.NEXT_PUBLIC_AWS_REGION,
tokenProvider: () => getChatToken(username),
})
chatRoom.connect();
chatRoom.logLevel = 'info'
setRoom(chatRoom)
}, [username])
return { room }
}
export const START_AUCTION_EVENT = 'start_auction'
export const END_AUCTION_EVENT = 'end_auction'
export const SEND_BID = 'send_bid'
We’ve used NextJS’s Route Handlers feature to create the API. The route of the API is as follows:
src/app/api/chatToken/route.js
import { IvschatClient, CreateChatTokenCommand, ChatTokenCapability } from "@aws-sdk/client-ivschat"
export async function POST(request) {
const { username } = await request.json();
const client = new IvschatClient({
region: process.env.NEXT_PUBLIC_AWS_REGION,
})
const input = {
roomIdentifier: process.env.NEXT_PUBLIC_CHATROOM_ID, // required
userId: username, // required
capabilities: [ChatTokenCapability.SEND_MESSAGE],
};
const command = new CreateChatTokenCommand(input);
const createChatTokenResponse = await client.send(command);
return Response.json(createChatTokenResponse);
}
Here, we are using an action CreateChatTokenCommand
from IVS Chat API.
For chat capabilities, we can allow users to either SEND_MESSAGE
| SEND_MESSAGE
| DISCONNECT_USER
| DELETE_MESSAGE
, But in this case, we just added SEND_MESSAGE
so all users can send bids as messages.
For roomIdenfier
, we have to use the Chatroom ID and copy it in the env file. Refer to the github README for creating chat rooms in console.
2. Create an auction form
After chat token is created and users are ready to send messages, we can create UI for Streamer (Auctioneer) to create an auction.
For this project we’re using product name, description of the item, duration in minutes, starting bid and image link (optional).
You can build your UI form however you like to collect the auction information. Our UI form can be found here:
src/app/components/StartAuctionForm
3. Start bid (Streamer)
After the Start Auction button is clicked, a chat message will be sent in the room with all the auction information and whoever is in that chat room will receive this.
You can use the class SendMessageRequest to send a message in the chat room.
You would need to send parameters content
(required) and attributes
(optional).
new SendMessageRequest(content: string, attributes?: Record<string, string>)
The parameter content
has a 1KB limit on the message length whereas attributes
do not have a size restriction. For this project we decided to use the attribute
property to send the auction information since it does not have the size limit.
src/app/utils/useAdmin.js
import { SendMessageRequest} from 'amazon-ivs-chat-messaging'
import { START_AUCTION_EVENT } from './useChatTokenSetup'
const sendStartAuction = (room, product) => {
const request = new SendMessageRequest('skip', {
eventType: START_AUCTION_EVENT,
product: JSON.stringify(product),
})
room.sendMessage(request)
}
Since content
is required, we put a random string skip
as a placeholder. But it can be anything because we won’t be using it.
For the attributes, we are just passing the eventType
and product
.
The attribute eventType
determines what actions we can take when receiving the chat message.
4. Receive StartBid (Viewer)
After createToken is created, we can add a addListener
function to the chat room to immediately receive any messages sent by anybody in the chat room.
As previously mentioned, we can use the eventType
attribute to decide which action to take.
In this case, we are calling a redux action changeAuctionStatus
to update the status of the auction.
src/app/utils/useUser.js
const { username } = useSelector(state => state.auction)
const { room } = useChatTokenSetup(username)
const { changeActionStatus } = useActions()
useEffect(() => {
if (eventType === START_AUCTION_EVENT) {
const receivedProduct = JSON.parse(message.attributes.product)
//This is an action to update auction state
changeAuctionStatus({
status: constants.AUCTION_STATUS.STARTED,
product: receivedProduct,
maxBid: {
bidValue: receivedProduct.initialBid,
bidSender: null
},
bidResult: null,
})
}
}, [room, username])
When the state of the auction changes, it will update the UI for the Bidders.
5. Send bid (Viewer)
Once the auction starts, viewers can start bidding. Again, the bidding
action can be sent in the chat room as a message
. Let’s see how it’s done.
When a viewer updates the max bidding price, and clicks the Bid button, the following happens in the background:
src/app/utils/useUser.js
const sendBid = async (bid) => {
const request = new SendMessageRequest('skip', {
eventType: SEND_BID,
bidValue: bid,
})
try {
await room.sendMessage(request);
} catch (error) {
console.log(error);
}
}
Again, we’re just using skip
string for the content parameter as a placeholder, and we’re adding 2 attributes, eventType:SEND_BID
and the bidValue
.
6. Receive bid message (Viewer and Streamer)
Both Streamer and Viewer can listen to the message and take action accordingly when eventType is SEND_BID
.
When the eventType is a SEND_BID
, a redux action bidAuction
is fired to update the maxValue and the bidder. The bidResult
state becomes HIGHEST
when a viewer is the highest bidder.
src/app/utils/useUser.js
const { username } = useSelector(state => state.auction)
const { room, SEND_BID } = useChatTokenSetup(username)
const { bidAuction } = useActions()
useEffect(() => {
const unsubscribeOnMessage = room.addListener('message', (message) => {
const { eventType } = message.attributes
const { userId } = message.sender
...
if (eventType === SEND_BID) {
//This is an action to update auction maxBid value and user
bidAuction({
bidValue: message.attributes.bidValue,
bidSender: userId,
bidResult: username === userId ? bidTypes.HIGHEST : null, //null for admin
})
}
return () => {
unsubscribeOnMessage()
}
})
}, [room, username])
Once the redux state maxBid
updates, it will appear in the UI as the result.
In the screenshot below, a viewer is bidding with a higher price, and the UI gets updated after receiving the chat message.
7. End auction
There are 2 ways to end an auction.
- A streamer (admin) can stop the auction midway, even when the timer is not over yet.
- Another way an auction ends is when the timer is done.
This endAuction()
function fires whenever the auction ends.
Like starting the auction, we can also send an END_AUCTION_EVENT
as a message to the chat room.
src/app/utils/useAdmin.js
const endAuction = async (type, maxBidder) => {
const request = new SendMessageRequest('skip', {
eventType: END_AUCTION_EVENT,
bidResult: type, //either CANCELLED, NO_BID or SOLD
maxBidder: maxBidder
})
try {
await room.sendMessage(request)
} catch (error) {
console.log('Cannot end auction: ', error)
}
}
8. Receive end auction and show bid results
In the END_AUCTION_EVENT
, we are checking which type of result it was, SOLD
(item was sold), WINNER
(viewer who won the bid), NOBID
(nobody bade) or CANCELLED
(admin canceled the auction).
Depending on the result the UI would show the result accordingly.
src/app/utils/useUser.js
const { username } = useSelector(state => state.auction)
const { room, SEND_BID } = useChatTokenSetup(username)
const { bidAuction } = useActions()
useEffect(() => {
const unsubscribeOnMessage = room.addListener('message', (message) => {
const { eventType } = message.attributes
const { userId } = message.sender
...
if (eventType === END_AUCTION_EVENT) {
const messageBidResult = message.attributes.bidResult
const maxBidder = message.attributes.maxBidder
const userBidResult = ((messageBidResult === bidTypes.SOLD) && (maxBidder === username)) ? bidTypes.WINNER : messageBidResult
changeAuctionStatus({ status: constants.AUCTION_STATUS.FINISHED, bidResult: userBidResult })
}
})
return () => {
unsubscribeOnMessage()
}
})
}, [room, username])
Conclusion
In this post we have learned the following:
- Demonstrating how we can use IVS Chat to create a bidding auction app
- How viewers join in a chat room by using CreateChatToken
- How to send messages with SendMessageRequest
- How to send attributes in a message
- How to receive messages by listening to the “message” event
- How to handle the messages received
Four Nine is a full-service Digital Agency located in Vancouver, BC. Learn more about us by visiting our website or contact us at info@fournine.digital.