Share a File over a WebRTC Data Channel with Twilio Video
Time to read: 10 minutes
When you're taking part in a video conversation, sometimes you have files you want to share with the other people on the call so that everyone can take a look. This is a great way to collaborate with your friends or colleagues when you're not in the same room or looking at the same screen.
In this tutorial, you'll build a video application with JavaScript and learn how to use the Twilio Video DataTrack API to share a file over WebRTC with the other participants on the call.
Follow along below step by step, or if you're interested in skipping ahead to take a look at the code, visit the project repository on GitHub here.
Let's get started!
Prerequisites
- A free Twilio account. (If you register here, you'll receive $10 in Twilio credit when you upgrade to a paid account!)
- Node.js v14+ and npm installed on your machine.
- ngrok
Create the project directory and install dependencies
From your terminal or command prompt, navigate to where you would like to set up your project. Create a new directory called data-track-file-share and change into that directory by running the following commands in your terminal:
Next, set up a new Node.js project with a default package.json file by running the following command:
Once you have your package.json file, you're ready to install the needed dependencies.
For this project, you will need the following packages:
- Express, a Node.js framework
- Twilio Node Helper Library, to use the Twilio APIs
- dotenv, to load the environment variables from a .env file into your application
- node-dev, to automatically restart the Node process when you modify a file
Run the following command in your terminal to install these packages:
If you check your package.json file now, you'll notice that the packages above have been installed as dependencies
.
Save your Twilio credentials safely as environment variables
Create a new file named .env at the root of your project and open it in your code editor. The .env file is where you will keep your Twilio account credentials. Add the following variables to your new file:
You’ll need to replace the placeholder text above with your actual Twilio credentials, which can be found in the Twilio Console. Log in to the Twilio Console and find your Account SID:
Copy and paste the value for Account SID to replace the placeholder text for TWILIO_ACCOUNT_SID
.
Then, navigate to the API Keys section of the console and generate a new API Key. Copy the API Key's values for SID and Secret to replace the placeholder text for TWILIO_API_KEY_SID
and TWILIO_API_KEY_SECRET
.
It’s important to keep these private credentials secure and out of version control. If you’re using GitHub, create a .gitignore file at the root of your project. Here you can list the files and directories that you want git to ignore from being tracked or committed. Open .gitignore in your code editor and add the .env file and the node_modules directory:
Now that you have your Twilio credentials set up, it's time to create your Express server.
Create a new Express server
Create a new file called server.js at the root of your project. This is the place where you will write your server-side code.
Open up server.js in your code editor. Add the following lines of code to server.js, which will load the environment variables from your .env file, create a new Express application, and set the application to run on port 5000:
Now, open package.json in your code editor. Inside the scripts
section, add a start
script as shown below. You can remove the placeholder test
script that was automatically generated by npm init -y
earlier. Then, in the main
section, change the entry file listed there to server.js
. When you are finished, your package.json file should look like the code below:
Now, to run the start
script, return to your terminal window and run the following command:
Once you have done this, you should see the following log statement in your terminal window, letting you know that the Express server is running:
Now that your server is running, it's time to lay out the client side of your application.
Build the application layout and serve static files
Create a new directory called public at the root of your project. This directory will hold your static files:
Inside the public directory, create 3 new files: app.js, index.html, and styles.css.
Open public/index.html in your code editor and add the following code to the file:
The HTML code above creates the layout for your video chat application. In the <head>
, you have a link to the CSS styles, as well as two <script>
tags: one for the latest version of the Twilio Video library, and one for the JavaScript code you'll write later in this tutorial.
In the <body>
of your HTML, there are three <section>
elements:
gallery
, which will include all participants' audio and videocontrols
, which contains the controls for a user to join or leave the video room, as well as the controls for selecting and sharing filesfiles
, where the shared files will appear for participants to download
Now that you have the HTML, open public/styles.css. Copy the CSS from this repository and paste it into your file.
Now that you have some public files, you need to set up your server to serve these files when a user navigates to http://localhost:5000/ in their browser.
Return to server.js in your code editor. Add the following code to the file just below your constant definitions:
This code will add some Express middleware to your application, allowing it to parse JSON and to serve the static files you just created.
Now that you have a layout set up, the next step is to add JavaScript on the client side to show the user a preview of their video feed.
Display a video preview for the local participant
Open public/app.js in your code editor. Add the following lines of code to set up the variables you will need for this part of the project:
The first sets of variables refer to the HTML sections, inputs, and buttons in your app. After that, you have a variable that creates a new Twilio Video LocalDataTrack
, which will be used later on to share files among participants. Following that are the variables for the room name — in this case, my-video-room
— and a variable for the actual Twilio videoRoom
that the participant will join.
Next, paste the following code just below your list of variables. This is the function that will add a user's local video feed to the application:
In the addLocalVideo()
function, you create a LocalVideoTrack
, then attach it to a <div>
and attach that <div>
to the gallery
section of your UI. This is where the preview video will appear.
Just below where the addLocalVideo()
function is declared, call the function:
You can see your video preview if you navigate to http://localhost:5000/ in your browser:
Generate an Access Token for joining video rooms
Now that you can see your own video preview, it's time to get ready to join an actual video call. In order to do this, you will add code to your Express server to generate a short-lived credential called an Access Token.
Open server.js in your code editor and add the following imports to the list at the top of the file:
Then, add the following /token route just below your route for serving static files but before the app.listen()
line:
How will your application use this /token endpoint?
When a participant navigates to your application, enters their username in the input field, then clicks the Join Room button, their name and the name of the video room will be passed to this endpoint via a POST
request.
The endpoint will then use your Twilio credentials and the Twilio Node Helper Library to create an access token specifically for this participant and this video room. Then, the endpoint will return the access token to the client side of your application. Your JavaScript code will then use this access token to connect to the video room.
Join the video room as a local participant
Now that you have the code for generating Access Tokens, it's time to write the code that will actually create the video room and let you join as a participant.
Return to public/app.js in your code editor. Just below your addLocalVideo()
function definition and above its invocation, add the following new function called joinRoom()
:
This function will handle when a user clicks the Join Room button. It will get the user's identity
from what they have entered in the <input>
field, then make a POST
request to the /token endpoint you added to your server in the previous section.
Once your application receives the access token from the server side, it takes the user's local tracks for audio, video, and data, then connects to the video room using the token and these tracks. A new <div>
is created with the participant's name (identity
) and their media tracks. The function then sets up event listeners to listen for when other participants join the video call.
Now that the joinRoom()
function is complete, it's time to create the function that will let users leave the video call. This function will disconnect a participant from the video room and remove all of the other participants' media from the UI.
Add the following leaveRoom()
function just below the one for joinRoom()
:
Now, at the bottom of public/app.js, add click
event listeners to the joinRoomButton
and leaveRoomButton
that will call joinRoom()
and leaveRoom()
respectively when users click on these buttons:
Now that you have a way for the local participant to join and leave the video room, it's time to add some code to handle the file sharing aspect of your application.
Send a file over the local data track
In order to send a file, participants in your video application will need to click the Choose File button in the UI. Once they have done this, the file selection window will appear, and they can select the file they would like to share with the rest of the participants on the call.
Let's add a function that will handle uploading this file and sending it over the data track. Add the following sendFile()
function to public/app.js, just below the leaveRoom()
function:
This function takes the selected file and converts it to an ArrayBuffer, which is a representation of the file as an array of bytes that can be sent over the local data track. A notification will then appear in the files
section to let the local participant know that the file was sent.
Now that you have the function for sending the file, add the following new event listener to the event listeners section at the bottom of public/app.js. This new listener will call the sendFile()
function when a user clicks on the shareFileButton
:
Now that you have a way for the local participant to send a file over the data track, it's time to add code to handle connecting the other participants to the video room and setting them up to receive the shared files.
Connect remote participants to the video room
You may have noticed, in the joinRoom()
function you added before, that when a participantConnected
event occurs in the video room, the function participantConnected()
gets called. A similar thing occurs for the participantDisconnected
event. It's time to add these two functions to the code in public/app.js.
Add the following participantConnected()
function to the file, just below the sendFile()
function:
The participantConnected()
function creates a new <div>
for each remote participant when they connect to the room, displays their username (identity
), and attaches their video and audio tracks to the <div>
.
It also creates event listeners for when these remote participants publish or unpublish their tracks — if someone starts or stops sharing their media, your application can attach or detach these tracks from the UI as needed.
Additionally, this function sets up a listener for when a shared file is received over the data track. When another participant shares a file, the received array of bytes is converted to a Blob object. Then, the application creates a clickable link to this file object using the file emoji (📄) and adds it to the files
section in the UI. Now the other participants in the video call will be able to download the file that their friend has uploaded.
Now that you have code for participantConnected()
, add the following participantDisconnected()
function just below that:
This function logs a message to the console about which participant has left the call and removes their <div>
from the UI.
Your video chat is fully functional now. Before you test it out, let's run the application on ngrok so that it is easy to test with a friend.
Set up an ngrok tunnel
In this project, you'll be using ngrok to connect the Express application running locally on your machine to a temporary public URL. To start a new ngrok tunnel, open up a new terminal window and run the following command:
Once ngrok is running, you will see text similar to the below in your terminal window:
Copy the https:// URL next to Forwarding
. Any requests that are made to this ngrok URL will be forwarded to your local server. You now have a temporary link to your application that you can share with a friend or colleague!
It's time to test your application and try sending a file.
Send a text file in your video chat application
Create a new file on your machine called secretNote.txt. Open this file and add a short message. The message can be whatever you wish, but here is what I added:
Open the https:// ngrok forwarding URL in a browser window. Your video application will load and you will be able to see your video preview.
Enter your name in the input field and click the Join Room button to connect to the video room.
If you are testing this application on your own, open the same URL in a second browser window and join the call again with a different name. If you are testing this application with a friend, wait for your friend to join the video call. You will be able to see everyone's video feed on your screen.
Once everyone has joined the call, click the Choose File button and select secretNote.txt.
Once the file has been selected, click the Share File button to send the file to the other participants on the call. A File sent notification will appear for the participant who shared the file:
The file will be sent via the data track to the other participants, and they will see a file emoji appear in the blue section at the bottom of the screen.
Click on the file image to download the file to your computer. If you open the file, you will be able to read the secret message!
What's next for sharing files in your video chat?
You've just built a cool video chat application with a file sharing feature. This could be the beginning of a very interesting and fun project. Perhaps you're interested in making your application even more fun by adding some emoji confetti to your video chat. Or perhaps the file sharing aspect of this project was more interesting to you, and you're interested in adding a shared notepad to your chat as well?
If you would like to see the code for this project in its entirety, check out the repository on GitHub here.
There are so many exciting things you can create with this. I can't wait to see what you build!
Mia Adjei is a Software Developer on the Developer Voices team. They love to help developers build out new project ideas and discover aha moments. Mia can be reached at madjei [at] twilio.com.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.