TypeScript Quick Start
This tutorial shows how to use Fishjam from plain TypeScript, without any UI framework.
It uses @fishjam-cloud/ts-client, the same client that powers the React SDK. There are no hooks or providers: you call methods and listen to events.
What you'll build​
A single web page that joins a room, publishes your camera and microphone, and shows everyone else in the room.
What you'll learn​
- How to connect to a room with
FishjamClient - How to publish your camera and microphone
- How to display tracks from other participants
- How to leave the room
Prerequisites​
- A TypeScript web project with a bundler, for example
npm create vite@latest my-app -- --template vanilla-ts - Access to Fishjam Dashboard
Step 1: Install and set up​
Install the package​
- npm
- Yarn
- pnpm
- Bun
npm install @fishjam-cloud/ts-client
yarn add @fishjam-cloud/ts-client
pnpm add @fishjam-cloud/ts-client
bun add @fishjam-cloud/ts-client
Get your Fishjam ID and Sandbox API URL​
- Log in to Fishjam Dashboard
- Navigate to the Sandbox tab
- Copy your Fishjam ID
- Copy your Sandbox API URL from the Sandbox API section
Step 2: Get a peer token​
Every peer needs a peer token to join a room. For testing, request one from the Sandbox API:
// Check https://fishjam.io/app/sandbox for your Sandbox API URL constSANDBOX_API_URL = "YOUR_SANDBOX_API_URL"; async functiongetPeerToken (roomName : string,peerName : string) { consturl = newURL (SANDBOX_API_URL );url .searchParams .set ("roomName",roomName );url .searchParams .set ("peerName",peerName ); constresponse = awaitfetch (url ); const {peerToken } = awaitresponse .json (); returnpeerToken as string; }
The Sandbox API is for prototyping only. In production, get the peer token from your own backend.
Step 3: Connect to a room​
Create a FishjamClient and call connect. The returned promise resolves once you have joined the room:
import {FishjamClient } from "@fishjam-cloud/ts-client"; // Check https://fishjam.io/app/ for your Fishjam ID constFISHJAM_ID = "YOUR_FISHJAM_ID"; constclient = newFishjamClient (); constpeerToken = awaitgetPeerToken ("testRoom", `user_${Date .now ()}`); awaitclient .connect ({url : `wss://fishjam.io/api/v1/connect/${FISHJAM_ID }`,token :peerToken ,peerMetadata : {}, });
Step 4: Publish your camera and microphone​
Get a MediaStream from the browser and add each of its tracks to the client:
constlocalStream = awaitnavigator .mediaDevices .getUserMedia ({video : true,audio : true, }); for (consttrack oflocalStream .getTracks ()) { awaitclient .addTrack (track , {type :track .kind === "video" ? "camera" : "microphone",paused : false, }); } // Show your own video (muted, so you don't hear yourself) constmyVideo =document .createElement ("video");myVideo .autoplay = true;myVideo .muted = true;myVideo .srcObject =localStream ;document .body .appendChild (myVideo );
Step 5: Display other participants​
The client emits trackReady when media from another peer starts arriving, and trackRemoved when it stops.
Register these listeners before calling connect, so you also receive the tracks of peers who are already in the room:
client .on ("trackReady", (ctx ) => { if (!ctx .track ) return; constelement =document .createElement (ctx .track .kind === "video" ? "video" : "audio", );element .id =ctx .trackId ;element .autoplay = true;element .srcObject = newMediaStream ([ctx .track ]);document .body .appendChild (element ); });client .on ("trackRemoved", (ctx ) => {document .getElementById (ctx .trackId )?.remove (); });
Step 6: Leave the room​
client .disconnect ();
Complete example​
index.html:
<!doctype html> <html> <body> <button id="join">Join</button> <button id="leave">Leave</button> <div id="videos"></div> <script type="module" src="/src/main.ts"></script> </body> </html>
src/main.ts:
import {FishjamClient } from "@fishjam-cloud/ts-client"; // Check https://fishjam.io/app/ for your Fishjam ID // Check https://fishjam.io/app/sandbox for your Sandbox API URL constFISHJAM_ID = "YOUR_FISHJAM_ID"; constSANDBOX_API_URL = "YOUR_SANDBOX_API_URL"; constvideos =document .getElementById ("videos")!; constclient = newFishjamClient (); letlocalStream :MediaStream | undefined; async functiongetPeerToken (roomName : string,peerName : string) { consturl = newURL (SANDBOX_API_URL );url .searchParams .set ("roomName",roomName );url .searchParams .set ("peerName",peerName ); // For production apps, get the peerToken from your own backend instead constresponse = awaitfetch (url ); const {peerToken } = awaitresponse .json (); returnpeerToken as string; } functionaddMediaElement (id : string,track :MediaStreamTrack ,muted = false) { constelement =document .createElement (track .kind === "video" ? "video" : "audio", );element .id =id ;element .autoplay = true;element .muted =muted ;element .srcObject = newMediaStream ([track ]);videos .appendChild (element ); }client .on ("trackReady", (ctx ) => { if (ctx .track )addMediaElement (ctx .trackId ,ctx .track ); });client .on ("trackRemoved", (ctx ) => {document .getElementById (ctx .trackId )?.remove (); }); async functionjoin () { constpeerToken = awaitgetPeerToken ("testRoom", `user_${Date .now ()}`); awaitclient .connect ({url : `wss://fishjam.io/api/v1/connect/${FISHJAM_ID }`,token :peerToken ,peerMetadata : {}, });localStream = awaitnavigator .mediaDevices .getUserMedia ({video : true,audio : true, }); for (consttrack oflocalStream .getTracks ()) { awaitclient .addTrack (track , {type :track .kind === "video" ? "camera" : "microphone",paused : false, }); } constmyVideo =localStream .getVideoTracks ()[0]; if (myVideo )addMediaElement ("my-video",myVideo , true); } functionleave () {client .disconnect ();localStream ?.getTracks ().forEach ((track ) =>track .stop ());videos .replaceChildren (); }document .getElementById ("join")!.addEventListener ("click",join );document .getElementById ("leave")!.addEventListener ("click",leave );
Run npm run dev, open the page in two browser tabs and click Join in both.
Next steps​
- Everything the TypeScript client can do: simulcast, data channels, livestreaming and more
- Set up your own backend to create peer tokens in production
- Understanding Fishjam architecture
- Rooms