const callType = "default";
const callId = "test-call";
const call = client.call(callType, callId);
await call.getOrCreate();
// or create it with options:
await call.getOrCreate({
data: {
/* call creation options */
},
});Joining & Creating Calls
This guide covers creating, joining, leaving, and ending calls, including ring calls.
Best Practices
- Handle
call.join()errors with try/catch - network issues can cause failures. - Always call
call.leave()when unmounting to prevent memory leaks. - Use
call.getOrCreate()when you want to create if not exists, or just load if it does. - Set
create: trueincall.join()only when you want to create the call on join. - For recurring meetings, reuse the same call ID (e.g., your appointment ID).
Call
Call is the main building block of the SDK, abstracting user actions, join flows, and call state.
Create call
Specify callType and callId to create a call. The Call Type controls permissions and features. Call IDs can be reused for recurring meetings.
See all options at the Call creation options section.
Join call
const callType = "default";
const callId = "test-call";
const call = client.call(callType, callId);
await call.join();Create and join a call
Set create: true to create a new call if it doesn't exist. Set it to false to only join an existing call.
await call.join({
create: true,
data: {
/* call creation options */
},
});Join with mic and camera on or off
Configure devices before joining (typically in a lobby view):
const call = client.call("default", "test-call");
// enable mic and camera
await call.camera.enable();
await call.microphone.enable();
// alternatively, you can disable them
await call.camera.disable();
await call.microphone.disable();
// and then join the call
await call.join();Leave call
await call.leave();End call
Ending terminates the call for everyone. Requires a special permission.
await call.endCall();Only users with OwnCapability.JOIN_ENDED_CALL can join an ended call.
Load call
const call = client.call(type, id);
await call.get(); // just load
await call.getOrCreate(); // create if not present and load itThese operations initialize call.state and subscribe to real-time updates.
More: Call & Participant State
Update call
import { RecordSettingsRequestModeEnum } from "@stream-io/video-react-sdk";
await call.update({
custom: { color: "green" },
settings_override: {
recording: {
mode: RecordSettingsRequestModeEnum.DISABLED,
},
},
});Call creation options
| Option | Description | Default |
|---|---|---|
members | A list of members to add to this call. You can specify the role and custom data on these members | - |
custom | Any custom data you want to store | - |
settings | You can overwrite certain call settings for this specific call. This overwrites the call type standard settings | - |
startsAt | When the call will start. Used for calls scheduled in the future, livestreams, audio rooms etc | - |
team | Restrict the access to this call to a specific team | - |
ring | If you want the call to ring for each member | false |
notify | If you want the call to notify each member by sending push notification. | false |
video | When ringing, the notification will indicate whether it’s a video call or an audio-only call, depending on whether you set the video parameter to true or false | - |
Set call members
const call = client.call(type, id);
await call.getOrCreate({
data: {
members: [{ user_id: "alice", role: "admin" }, { user_id: "bob" }],
},
});Update call members
await call.updateCallMembers({
update_members: [{ user_id: "charlie", role: "admin" }],
remove_members: ["alice"],
});Multi-tenant & teams
Users in a team must specify the same team when creating calls:
const call = client.call(type, id);
await call.getOrCreate({
data: { team: "red" },
});Ensure call IDs are unique - use UUIDs or prefix with team name.
Custom call data
await call.getOrCreate({
data: {
custom: { color: "blue" },
},
});Settings override
Override call type settings for a specific call:
// at creation time
await call.getOrCreate({
data: {
settings_override: {
audio: { mic_default_on: false },
video: { camera_default_on: false },
},
},
});
// or later
await call.update({
settings_override: {
video: { camera_default_on: true },
},
});Backstage setup
The backstage feature lets you and your co-hosts set up before going live. Only after call.goLive() will regular users be allowed to join.
You can also specify join_ahead_time_seconds to allow users to join before the call goes live:
await call.getOrCreate({
data: {
starts_at: new Date(Date.now() + 500 * 1000), // 500 seconds from now
settings_override: {
backstage: {
enabled: true,
join_ahead_time_seconds: 300,
},
},
},
});In this example, the call starts 500 seconds from now with backstage enabled and join_ahead_time_seconds of 300. Regular users can join 200 seconds from now (500 - 300).
Restricting access
Control access by configuring Call Type permissions.
Step 1: Set up the roles and permissions
On the dashboard, navigate to Video & Audio -> Roles & Permissions and select the appropriate role and scope.
By default, all users have the user role. Start by removing the JoinCall permission from the user role for your call type scope. This prevents regular users from joining calls of this type.

Next, ensure the call_member role has the JoinCall permission. This allows users with the call_member role to join calls of this type.

Step 2: Set up the call
const call = client.call("my-call-type", "my-call-id");
await call.getOrCreate({
data: {
members: [
// please note the `role` property
{ user_id: "alice", role: "call_member" },
{ user_id: "bob", role: "call_member" },
],
},
});
// Grant access to more users
await call.updateCallMembers({
update_members: [{ user_id: "charlie", role: "call_member" }],
});
// Remove access
await call.updateCallMembers({
remove_members: ["charlie"],
});