Auction App Demo with Amazon Interactive Video Service Chat and ReactJS

Ayako Sayama
Four Nine Digital
Published in
8 min readFeb 7, 2024

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:

Streaming starting an auction and stream to sell items

In this article, you’ll learn about

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:

  1. Create a ChatToken
  2. Create an auction form
  3. Start bid (Streamer)
  4. Receive start bid (Viewer)
  5. Send bid (Viewer)
  6. Receive bid message (Streamer and Viewer)
  7. End auction
  8. 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_MESSAGEso 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

Auction form for the streamer

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.

Example of viewer’s auction card automatically updating after auction starts

5. Send bid (Viewer)

Once the auction starts, viewers can start bidding. Again, the biddingaction 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_BIDand 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.

Example of a viewer bidding and getting the highest bid

7. End auction

There are 2 ways to end an auction.

  1. A streamer (admin) can stop the auction midway, even when the timer is not over yet.
  2. 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])
Various UI results when an auction is finished

Conclusion

In this post we have learned the following:

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.

--

--