Build a Video Calling App on AWS With Lambda and Amazon Chime SDK

New
5 min read
Pratik K
Pratik K
Published April 22, 2025

This tutorial covers building the full stack video calling application using Amazon Chime SDK and AWS Lambda.

Video calling applications need a specialized server setup to handle real-time video streaming. Building and maintaining such servers for one application is challenging. Hence, services like Amazon Chime SDK or Stream Video API provide API-based access to these backend servers. You can simply call their APIs and leverage the infrastructure required for real-time streaming.

In this tutorial, you will learn how to use these APIs by building a full-stack video-meet application. The application will allow users to create and join meetings, share screens, and use audio/video controls. The front end is built using React, leveraging the Chime-react-component library. The backend has two lambda functions using the Chime SDK, which is served via an API gateway.

Developer Setup

You need an AWS account and local setup with AWS CLI, nodejs, and NPM installed.

Use the below steps to set up the front-end application.

  1. Start by creating a basic React app
    bash
    1
    $ npx create-react-app video-meet-app \--template typescript
  2. Change directory
    bash
    1
    $ cd video-meet-app
  3. Install dependencies
    bash
    1
    $ npm install
  4. Install the Amazon Chime SDK React Component Library and peer dependencies
    bash
    1
    $ $ npm install --save amazon-chime-sdk-component-library-react amazon-chime-sdk-js styled-components styled-system aws-amplify && npm install --save-dev @types/styled-components
  5. (optional) Adjust the react version in case of an ERESOLVE error
    bash
    1
    $ npm install react@18 react-dom@18

Setting Up Frontend

In this step, we create the front-end code and put it in the src directory inside the video-meet-app project directory.

Make sure you are inside this directory and clone this repository - https://github.com/pratiksk/aws-chime-sdk-video-meet.git.

It will populate the src directory along with package.json and tsconfig.json files. The final project structure should look like -

text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
├── README.md ├── build │ ├── asset-manifest.json │ ├── index.html │ └── static │ └── js ├── package-lock.json ├── package.json ├── public │ └── index.html ├── src │ ├── components │ │ ├── Meeting.tsx │ │ └── MeetingForm.tsx │ ├── index.tsx │ └── utils │ └── api.ts └── tsconfig.json

Some important code snippets are as follows.

MeetingForm.jsx contains the core logic of creating and joining meetings.

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Core logic for creating or joining a meeting let joinInfo; if (\!title) { // Create a new meeting if no meeting ID is provided const meetingResponse \= await createMeeting(\`meeting-${Date.now()}\`); joinInfo \= await joinMeeting(meetingResponse.meeting.MeetingId, name); } else { // Join an existing meeting joinInfo \= await joinMeeting(title, name); } const meetingSessionConfiguration \= new MeetingSessionConfiguration( joinInfo.meeting, joinInfo.attendee ); console.log('Joining with configuration:', { meetingId: joinInfo.meeting.MeetingId, attendeeId: joinInfo.attendee.AttendeeId }); await meetingManager.join(meetingSessionConfiguration, { deviceLabels: DeviceLabels.AudioAndVideo }); await meetingManager.start();

Meeting.jsx file handles the functionality of the actual meeting after it is created and joined by users. The following code snippet shows that the video tile status is maintained as users join or leave.

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const Meeting: React.FC \= () \=\> { const meetingManager \= useMeetingManager(); const meetingStatus \= useMeetingStatus(); const { tiles } \= useRemoteVideoTileState(); const { isVideoEnabled } \= useLocalVideo(); // Log when remote video tiles change useEffect(() \=\> { console.log('Remote video tiles:', tiles); }, \[tiles\]); const handleEndMeeting \= async () \=\> { await meetingManager.leave(); window.location.reload(); // Simple way to get back to the form };

App.ts handles API calls to the backend lambda function. Make sure to paste your API URL in this file.

typescript
1
2
3
4
5
6
7
8
9
10
11
12
const API\_URL \= "YOUR API URL HERE"; \`\`\` Create a new meeting \`\`\`typescript export async function createMeeting(meetingId: string): Promise\<CreateMeetingResponse\> { try { const response \= await fetch(\`${API\_URL}/create-meeting\`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ meetingId }), }); }

Join an existing meeting

typescript
1
2
3
4
5
6
7
8
export async function joinMeeting(meetingId: string, attendeeName: string): Promise\<JoinMeetingResponse\> { try { const response \= await fetch(\`${API\_URL}/join-meeting\`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ meetingId, attendeeName }), }); }

Setting Up Backend

The backend consists of two lambda functions: one for creating a meeting using the Chime SDK and the other for joining it. These lambda functions are served via HTTP API Gateway using proxy integration.

Building your own app? Get early access to our Livestream or Video Calling API and launch in days!

Lambda Functions

Refer to this git for code - https://github.com/pratiksk/backend-aws-chime-sdk-video-meet.git

create_meeting function creates a meeting using Amazon Chime SDK and sends the meeting ID and other relevant data in response

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import { ChimeSDKMeetings } from '@aws-sdk/client-chime-sdk-meetings'; // Create Chime SDK client const chimeSDKMeetings \= new ChimeSDKMeetings({ region: 'us-east-1' }); export const handler \= async (event) \=\> { try { const body \= JSON.parse(event.body || '{}'); const meetingId \= body.meetingId || \`meeting-${Date.now()}\`; const meetingResponse \= await chimeSDKMeetings.createMeeting({ ClientRequestToken: meetingId, MediaRegion: 'us-east-1', ExternalMeetingId: meetingId }); return { … } }) }; } };

join_meeting function handles attendees joining and returns meeting details and joining tokens

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { ChimeSDKMeetings } from '@aws-sdk/client-chime-sdk-meetings'; // Create client const chimeSDKMeetings \= new ChimeSDKMeetings({ region: 'us-east-1' }); export const handler \= async (event) \=\> { try { const body \= JSON.parse(event.body || '{}'); const meetingId \= body.meetingId; const attendeeName \= body.attendeeName || 'Anonymous'; if (\!meetingId) { return { statusCode: 400, body: JSON.stringify({ error: 'Missing meetingId parameter' }) }; } // Get the meeting using SDK v3 syntax const meeting \= await chimeSDKMeetings.getMeeting({ MeetingId: meetingId }); // Create a new attendee for the meeting const attendee \= await chimeSDKMeetings.createAttendee({ MeetingId: meetingId, ExternalUserId: \`${attendeeName}-${Date.now()}\` }); return { ... }) }; } };

API Gateway

Create HTTP API Gateway with two routes -

  1. create-meeting - integrate it to the create meeting lambda function
  2. join-meeting - integrate it to the join meeting lambda function

Select AWS Lambda from the integration type dropdown.
CORS is handled inside the code since we are using proxy integration. Make sure NOT to set CORS in API Gateway settings since it overrides the headers from the backend function. Browsers won’t be allowed to use API if this is not set up correctly.

Testing the Setup

bash
1
npm start
  1. Run this command and wait for the browser to open.
  2. Enter the user name, keep the meeting ID blank, and click the create/join button.
    For the first time, since the meeting does not exist already, the backend will create the meeting and send the meeting ID back.
  3. You will be joined inside the call automatically.
  4. Copy the meeting ID using the copy meeting ID button.
  5. Go to another browser, go to localhost, and join the meeting using this meeting ID. You should see the other user's video.
  6. Share screen using the share screen/content button.

Limitation: If you test from a single system, the camera is shared, and both users cannot use it simultaneously. To test, you can switch off one video and start another.

Optionally, you can expose your localhost to the internet or host the react frontend on S3 and serve using Cloudfront to test it with your friends.

AWS Chime SDK vs. Stream Video API

The main difference between Amazon Chime SDK and Stream Video lies in the backend setup. You need the backend setup with Amazon Chime SDK, but Stream can be directly called from the front-end application.

AWS Chime SDK uses an AWS’s IAM-based authentication system. Therefore, a service with proper AWS permissions (like lambda) is needed to talk with Chime SDK. For the front end to talk to lambda, you need to set up another API layer using AWS API Gateway (along with other technical setups like CORS)

Stream Video works based on tokens, which are safe to integrate into the front end. Step 2 of this tutorial shows how easy it is to implement. You just use the SDK to create or join meetings from your typescript code.

Stream also provides a rich React UI component library, which you can leverage to create a professional user experience.

Meeting interface joined from different machines
Screen sharing

Conclusion

Adding video streaming to your application provides an edge. However, it requires a complex backend architecture to stream live videos in real-time from multiple meeting attendees.

Ready-made solutions like Amazon Chime SDK simplify this by abstracting away those complexities. You can simply call APIs from the backend.

Stream simplifies it even further by providing a highly scalable video infrastructure that can be directly integrated into the front end. You can select an appropriate solution based on your requirements and current architecture.

Integrating Video With Your App?
We've built a Video and Audio solution just for you. Check out our APIs and SDKs.
Learn more ->