Optimize Video Tracks - React Native
Set the video track's quality to match your layout and network.
You can pass a custom video track for a participant's media before and during the room.
This page uses the following asynchronous methods. Refer to their API reference for the errors each Promise may reject with, and handle these rejections appropriately based on your use case.
Custom Video Track
This feature allows you to incorporate custom video encoder configurations, set the video quality profile (bitrateMode), control simulcast behavior (maxLayer), and choose the video codec, then send these modifications to other participants.
Once you set a custom video track created using createCameraVideoTrack(), VideoSDK remembers its settings and automatically reuses them whenever the webcam is turned back on. To change the track configuration, call disableCam(), then pass a new track created using createCameraVideoTrack() to enableCam(). VideoSDK accepts only tracks created using createCameraVideoTrack().
How to Create a Custom Video Track ?
- You can create a Custom Video Track using
createCameraVideoTrack()method of@videosdk.live/react-native-sdk. - This method can be used to create video track by specifying parameters like video resolution, camera facing mode, and the quality controls (
bitrateModeandmaxLayer). - The camera opens when you call this method, so you can preview the track before the room joins. The method does not ask the user for camera access, so get it first with
requestPermission()fromuseMediaDevice(). If you don't pass the track to the room, callstop()on it to close the camera. - You can choose video resolution from the below mentioned list of values for the encoder config:
| Encoder Config | Resolution | Optimized (kbps) | Balanced (kbps) | High Quality (kbps) |
|---|---|---|---|---|
| h90p_w160p | 160x90 | 40 | 90 | 120 |
| h180p_w320p | 320x180 | 60 | 120 | 180 |
| h360p_w640p | 640x360 | 300 | 450 | 600 |
| h540p_w960p | 960x540 | 600 | 900 | 1200 |
| h720p_w1280p | 1280x720 | 1000 | 1500 | 2000 |
| h1080p_w1920p | 1920x1080 | 1500 | 2200 | 2700 |
| h120p_w160p | 160x120 | 40 | 90 | 120 |
| h180p_w240p | 240x180 | 90 | 120 | 180 |
| h240p_w320p | 320x240 | 100 | 150 | 200 |
| h360p_w480p | 480x360 | 270 | 360 | 540 |
| h480p_w640p | 640x480 | 350 | 600 | 900 |
| h720p_w960p | 960x720 | 900 | 1200 | 1600 |
| h1080p_w1440p | 1440x1080 | 1500 | 2000 | 2700 |
Example
import { createCameraVideoTrack } from "@videosdk.live/react-native-sdk";
let customTrack = await createCameraVideoTrack({
// It will be the id of the camera from which the video should be captured.
cameraId: "camera-id", // OPTIONAL
// This will accept the resolution (height x width) of video you want to capture.
encoderConfig: "h720p_w960p", // "h360p_w640p" | "h480p_w640p" ... // Default : "h720p_w1280p"
// It will specify whether to use front or back camera for the video track.
facingMode: "front", // "back", Default : "front"
// This parameter will be discussed in the next step.
multiStream: true, // false, Default : true
// Optional: This controls the video quality and bandwidth usage.
bitrateMode: "HIGH_QUALITY", // "BANDWIDTH_OPTIMIZED" | "BALANCED" , Default : "BALANCED"
// Optional: This specifies the maximum number of simulcast layers (maxLayer) to publish.
maxLayer: 2, // 3 , Default: 3
// Optional: This specifies the video codec used to encode this track.
codec: "VP8", // "H264" | "VP9" | "AV1" , Default : "VP8"
});
The camera on the device limits how sharp the video can be. For example, if you set the encoder configuration to 1080p but the camera only supports 720p:
- On Android, the track uses the highest resolution the camera can capture, which in this case is 720p.
- On iOS, VideoSDK captures at the highest resolution the camera supports and scales it up. The video is sent at 1080p, but it is not sharper than what the camera captured.
What is multiStream?
- This parameter specifies whether the stream should send multiple resolution layers or a single resolution layer. It is
trueby default for a track created withcreateCameraVideoTrack(). - If you don't pass a custom track, the camera that VideoSDK opens for you takes
multiStreamfrom theconfigofRoomProviderinstead, where it also defaults totrue.
Refer to the Simulcast (Adaptive Bitrate) guide for the layers a track publishes and for how participants select the layer they receive.
What is BitrateMode?
BitrateMode lets you decide whether to prioritize sharp details, save internet data, or find a good balance between the two.
You can choose from three distinct modes:
BANDWIDTH_OPTIMIZED: Prioritizes lower bandwidth usage over video quality. Ideal for users with poor or unstable network conditions.BALANCED: The default setting. It balances clear video against bandwidth use, and suits most cases.HIGH_QUALITY: Prioritizes video quality over bandwidth usage. Use this when high-fidelity video is essential and viewers are expected to have strong network connections.
What is maxLayer?
- This parameter caps how many layers a track publishes, and accepts
2or3. It applies only whenmultiStreamistrue, and defaults to3.
Refer to the Simulcast (Adaptive Bitrate) guide for what each value publishes.
What is codec?
- This parameter specifies the video codec used to encode your stream. VideoSDK supports
VP8(default),H264,VP9, andAV1. Pass the codec as one of the strings"VP8","H264","VP9", or"AV1". - VideoSDK doesn't support
multiStreamforH264,VP9, andAV1.multiStreamdefaults totrue, so setmultiStream: falsewhen you create anH264,VP9, orAV1track. Otherwise VideoSDK sets it tofalsefor you and reportsERROR_MULTISTREAM_NOT_SUPPORTED(3046) through theonErrorcallback.
Refer to the Video Codecs guide to compare the four codecs, to check which codec a room is actually using, and to handle the cases where a codec is not supported.
How to Setup a Custom Video Track ?
The custom track can be configured both before and after the room is initialized. Following are the methods that help in doing so:
- Setting up a Custom Track during the initialization of a room
- Setting up a Custom Track with methods
1. Setting up a Custom Track during the initialization of a room
If you are enabling the webcam (camEnabled: true) in the config of RoomProvider and wish to use custom tracks from the start of the room, you can pass a custom track in the config as demonstrated below.
Custom Track will not apply on the camEnabled: false configuration.
Example
import { useEffect, useState } from "react";
import {
Constants,
createCameraVideoTrack,
RoomProvider,
useMediaDevice,
} from "@videosdk.live/react-native-sdk";
function App() {
const { requestPermission } = useMediaDevice();
const getTrack = async () => {
// createCameraVideoTrack() does not ask for access, so ask first.
await requestPermission(Constants.permission.AUDIO_AND_VIDEO);
const track = await createCameraVideoTrack({
encoderConfig: "h720p_w960p",
facingMode: "front",
multiStream: true,
bitrateMode: "HIGH_QUALITY",
maxLayer: 2,
codec: "VP8",
});
setCustomTrack(track);
};
let [customTrack, setCustomTrack] = useState(null);
useEffect(() => {
getTrack();
}, []);
return (
customTrack && (
<RoomProvider
config={{
roomId,
participantName: "John Doe",
micEnabled: true,
//If true, it will use the passed custom track to turn webcam on
camEnabled: true,
//Pass the custom video track here
customCameraTrack: customTrack,
}}
token={token}
>
<RoomView />
</RoomProvider>
)
);
}
2. Setting up a Custom Track with methods
To switch tracks during the room, you need to pass the CustomStreamTrack to the enableCam() method of useRoom.
Make sure to call the disableCam() method before you pass a new track to enableCam(). While the camera is on, enableCam() rejects with ERROR_ALREADY_IN_REQUESTED_STATE (3054). To replace the track while the camera is on, pass it to changeCam().
Example
import {
createCameraVideoTrack,
useRoom,
} from "@videosdk.live/react-native-sdk";
import { TouchableOpacity, Text } from "react-native";
const RoomControls = () => {
const { isCamEnabled, enableCam, disableCam } = useRoom();
const handleEnableWebcam = async () => {
if (isCamEnabled) {
try {
await disableCam();
} catch (err) {
console.error("disableCam failed:", err);
}
} else {
try {
let customTrack = await createCameraVideoTrack({
encoderConfig: "h720p_w960p",
facingMode: "front",
multiStream: true,
bitrateMode: "HIGH_QUALITY",
maxLayer: 2,
codec: "VP8",
});
await enableCam(customTrack);
} catch (err) {
console.error("enableCam failed:", err);
}
}
};
return (
<>
<TouchableOpacity
onPress={() => {
handleEnableWebcam();
}}
>
<Text>Enable Webcam</Text>
</TouchableOpacity>
</>
);
};
Pass only tracks created with the createCameraVideoTrack() method. RoomProvider, enableCam() and changeCam() do not accept other objects. A stopped or released track is refused with ERROR_INVALID_CUSTOM_VIDEO_TRACK (3029).
Which configuration is suitable for the Device ?
The chart below shows the encoder resolution and multiStream setting to use for each participant count.

Custom Screen Share Track
This feature enables the customization of screenshare streams with predefined encoder configuration (resolution + FPS) for specific use cases, which can then be sent to other participants.
How to Create Custom Screen Share Track ?
- You can create a Video Track using
createScreenShareVideoTrack()method of@videosdk.live/react-native-sdk. - This method enables the creation of a video track with different encoding parameters.
- On Android, the screen capture consent dialog appears when you create the track. On iOS,
enableScreenShare()opens the system broadcast picker, and sharing starts when the user taps Start Broadcast.
Example
import { createScreenShareVideoTrack } from "@videosdk.live/react-native-sdk";
let customShareTrack = await createScreenShareVideoTrack({
// This will accept the height & FPS of video you want to capture.
encoderConfig: "h720p_15fps", // `h360p_30fps` | `h1080p_30fps` // Default : `h720p_15fps`
// It will publish the profile's three bitrate layers instead of a single layer.
multiStream: false, // true, Default : false
// Android only: It will also share the system audio.
withAudio: true, // false, Default : false
});
encoderConfigacceptsh360p_30fps,h480p_15fps,h480p_30fps,h720p_5fps,h720p_15fps,h720p_30fps,h1080p_15fpsandh1080p_30fps.multiStreampublishes the profile's three bitrate layers as simulcast layers instead of a single layer. It isfalseby default.withAudioworks on Android 10 and later. The system audio is mixed into your microphone track, so muting the mic mutes both. On iOS, it has no effect.
How to Setup Custom Screen Share Track ?
In order to switch tracks during the room, you have to pass the CustomStreamTrack to the enableScreenShare() or toggleScreenShare() method of useRoom.
Make sure to call the disableScreenShare() method before you create a new track. While you are sharing, enableScreenShare() rejects with ERROR_ALREADY_IN_REQUESTED_STATE (3054), and toggleScreenShare() turns screen share off without using the track.
A stopped or released track is refused with ERROR_INVALID_CUSTOM_VIDEO_TRACK (3029).
Example
import {
createScreenShareVideoTrack,
useRoom,
} from "@videosdk.live/react-native-sdk";
import { TouchableOpacity, Text } from "react-native";
const RoomControls = () => {
const {
isScreenSharing,
enableScreenShare,
disableScreenShare,
toggleScreenShare,
} = useRoom();
const handleToggleScreenShare = async () => {
if (isScreenSharing) {
try {
await toggleScreenShare();
} catch (err) {
console.error("toggleScreenShare failed:", err);
}
} else {
try {
let customTrack = await createScreenShareVideoTrack({
encoderConfig: "h720p_15fps",
});
await toggleScreenShare(customTrack);
} catch (err) {
console.error("toggleScreenShare failed:", err);
}
}
};
const handleEnableScreenShare = async () => {
if (isScreenSharing) {
try {
await disableScreenShare();
} catch (err) {
console.error("disableScreenShare failed:", err);
}
}
try {
let customTrack = await createScreenShareVideoTrack({
encoderConfig: "h720p_15fps",
});
await enableScreenShare(customTrack);
} catch (err) {
console.error("enableScreenShare failed:", err);
}
};
return (
<>
<TouchableOpacity
onPress={() => {
handleToggleScreenShare();
}}
>
<Text>Toggle ScreenShare</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
handleEnableScreenShare();
}}
>
<Text>Enable ScreenShare</Text>
</TouchableOpacity>
</>
);
};
API Reference
The API references for all the methods and events utilised in this guide are provided below.
Got a Question? Ask us on discord

