Skip to content

Web SDK Adapters - Agora & Zego API Compatible

Monibuca Web SDK provides API adapter layers for Agora and Zego. These adapters expose the exact same API interfaces as the original vendor SDKs, but use Monibuca’s own WHIP/WHEP/WebSocket protocol stack under the hood — enabling zero cloud service costs with self-hosted deployment. Developers can migrate existing projects to Monibuca by changing just one import line.

ComparisonAgora / ZegoMonibuca Adapter
Cost ModelPer-minute billing, grows with scaleOne-time deployment, zero recurring costs
Data SovereigntyData routes through third-party cloudFully self-owned, never leaves your server
Migration CostChange one import line, zero code changes
Private DeploymentEnterprise license requiredOut-of-the-box
CustomizationLimited by vendor APIFully controllable, extensible
Protocol StandardProprietaryWHIP/WHEP open standards
User Code (Agora API) User Code (Zego API)
↓ ↓
@monibuca/adapter-agora @monibuca/adapter-zego
↓ ↓
└────────── @monibuca/sdk ───────────┘
WHIPClient / WHEPClient / RoomService
Monibuca Server
Terminal window
# Agora compatibility layer
pnpm add @monibuca/adapter-agora
# Zego compatibility layer
pnpm add @monibuca/adapter-zego

Both adapters depend on @monibuca/sdk, which will be installed automatically.


// Before (using Agora)
import AgoraRTC from "agora-rtc-sdk-ng";
// After (using Monibuca)
import { AgoraRTC } from "@monibuca/adapter-agora";
import { AgoraRTC } from "@monibuca/adapter-agora";
// Create client
const client = AgoraRTC.createClient({ mode: "rtc", codec: "h264" });
// Listen for remote user publishing
client.on("user-published", async (user, mediaType) => {
const track = await client.subscribe(user, mediaType);
if (mediaType === "video") {
track.play("remote-video-container");
}
if (mediaType === "audio") {
track.play();
}
});
client.on("user-left", (user) => {
console.log("User left:", user.uid);
});
// Join channel (appid = Monibuca server WebSocket URL)
const uid = await client.join("ws://your-server:8080", "channel-1", null, "user-1");
// Create local audio/video tracks
const [audioTrack, videoTrack] = await AgoraRTC.createMicrophoneAndCameraTracks();
// Preview local video
videoTrack.play("local-video-container");
// Publish to channel
await client.publish([audioTrack, videoTrack]);
MethodDescription
createClient(config)Create RTC client
createMicrophoneAudioTrack(config?)Create microphone audio track
createCameraVideoTrack(config?)Create camera video track
createScreenVideoTrack(config?)Create screen share track
createMicrophoneAndCameraTracks()Create audio + video tracks together
getCameras()Get camera device list
getMicrophones()Get microphone device list
getPlaybackDevices()Get playback device list
checkSystemRequirements()Check system requirements
MethodDescription
join(appid, channel, token, uid?)Join channel
leave()Leave channel
publish(tracks)Publish local tracks
unpublish(tracks?)Unpublish tracks
subscribe(user, mediaType)Subscribe to remote user
unsubscribe(user, mediaType?)Unsubscribe
EventWhen Triggered
user-joinedRemote user joined channel
user-leftRemote user left channel
user-publishedRemote user published audio/video
user-unpublishedRemote user unpublished
connection-state-changeConnection state changed
exceptionError occurred
MethodDescription
play(element?)Play/render track
stop()Stop playback
close()Close track and release resources
setEnabled(enabled)Enable/disable track
setVolume(volume)Set volume (audio tracks)
setDevice(deviceId)Switch device
getMediaStreamTrack()Get underlying MediaStreamTrack
Agora ParameterMonibuca Mapping
appidMonibuca WebSocket URL (e.g., ws://localhost:8180)
channelRoom ID (roomId)
uidUser ID (userId)
tokenNot used, pass null

// Before (using Zego)
import { ZegoExpressEngine } from "zego-express-engine-webrtc";
// After (using Monibuca)
import { ZegoExpressEngine } from "@monibuca/adapter-zego";
import { ZegoExpressEngine } from "@monibuca/adapter-zego";
// Create engine (appID is just an identifier, server = Monibuca server URL)
const zg = new ZegoExpressEngine(0, "ws://your-server:8080");
// Listen for room stream updates
zg.on("roomStreamUpdate", async (roomID, updateType, streamList) => {
if (updateType === "ADD") {
for (const stream of streamList) {
const remoteStream = await zg.startPlayingStream(stream.streamID);
document.getElementById("remote-video").srcObject = remoteStream;
}
}
if (updateType === "DELETE") {
for (const stream of streamList) {
zg.stopPlayingStream(stream.streamID);
}
}
});
// Listen for user updates
zg.on("roomUserUpdate", (roomID, updateType, userList) => {
console.log(`Users ${updateType}:`, userList);
});
// Login to room
const result = await zg.loginRoom("room-1", "", {
userID: "user-1",
userName: "John",
});
if (result.errorCode === 0) {
// Create local stream
const localStream = await zg.createZegoStream({
camera: { audio: true, video: true },
});
// Preview
document.getElementById("local-video").srcObject = localStream.stream;
// Publish stream
zg.startPublishingStream("stream-1", localStream);
}
MethodDescription
loginRoom(roomID, token, user, config?)Login to room
logoutRoom(roomID?)Logout from room
createZegoStream(source?)Create local stream (ZegoLocalStream)
createStream(source?)Create MediaStream
startPublishingStream(streamID, stream)Start publishing
stopPublishingStream(streamID)Stop publishing
startPlayingStream(streamID, option?)Start playing
stopPlayingStream(streamID)Stop playing
enumDevices()Enumerate devices
useAudioDevice(stream, deviceID)Switch audio device
useVideoDevice(stream, deviceID)Switch video device
sendBroadcastMessage(roomID, message)Send broadcast message
destroyEngine()Destroy engine
MethodDescription
enableCamera(enable)Enable/disable camera
enableMicrophone(enable)Enable/disable microphone
replaceVideoTrack(track)Replace video track
replaceAudioTrack(track)Replace audio track
destroy()Destroy stream
EventWhen Triggered
roomStateChangedRoom connection state changed
roomUserUpdateUser joined/left room
roomStreamUpdateRemote stream added/removed
publisherStateUpdatePublisher state changed
playerStateUpdatePlayer state changed
publishQualityUpdatePublish quality stats (every 2s)
playQualityUpdatePlay quality stats (every 2s)
IMRecvBroadcastMessageReceived broadcast message
roomOnlineUserCountUpdateOnline user count changed
Zego ParameterMonibuca Mapping
appIDApp identifier (for identification only, doesn’t affect connection)
serverMonibuca WebSocket URL (e.g., ws://localhost:8180)
roomIDRoom ID
userIDUser ID
streamIDStream path (streamPath)
tokenNot used, pass empty string

Both adapters use Monibuca SDK’s RoomService for signaling, WHIPClient for publishing, and WHEPClient for subscribing. The event mapping is:

Internal EventAgora EventZego Event
REMOTE_USER_ENTERuser-joinedroomUserUpdate(ADD)
REMOTE_USER_EXITuser-leftroomUserUpdate(DELETE)
user-publishuser-publishedroomStreamUpdate(ADD)
user-unpublishuser-unpublishedroomStreamUpdate(DELETE)
CONNECTION_STATE_CHANGEDconnection-state-changeroomStateChanged
WHIPClient statepublisherStateUpdate
WHEPClient stateplayerStateUpdate
chatIMRecvBroadcastMessage

  1. Server URL: The Agora adapter’s appid and Zego adapter’s server parameters should be set to the Monibuca server’s WebSocket URL
  2. Token Auth: Token authentication is not enforced in the current version; pass null or empty string
  3. Unsupported Features: Cloud recording, CDN relay, and other cloud service features are outside the adapter scope
  4. Quality Stats: Stream quality data comes from WebRTC native getStats() API, reported every 2 seconds
  5. Device Management: Device enumeration and switching uses the browser’s native mediaDevices API