Complete Usage Examples
::: code-group
<template>
<div class="app-container">
<div ref="containerRef" class="device-container"></div>
<div class="controls">
<div class="input-group">
<label class="label">Host IP:</label>
<input v-model="hostIp" placeholder="e.g., 192.168.10.50" class="input" />
<label class="label">Device Name:</label>
<input v-model="deviceName" placeholder="e.g., EDGE00M7EHBKZGVN" class="input" />
</div>
<div class="button-group">
<button @click="connect" class="btn btn-primary">Connect</button>
<button @click="disconnect" class="btn btn-secondary">Disconnect</button>
<button @click="handleHome" class="btn btn-action">Home</button>
<button @click="handleBack" class="btn btn-action">Back</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, shallowRef, markRaw, onMounted, onUnmounted } from "vue";
import {
VmosEdgeClient,
VmosEdgeClientEvents,
type VmosEdgeClientConfig,
type VmosEdgeErrorEvent,
} from "@vmosedge/web-sdk";
const containerRef = ref<HTMLElement | null>(null);
const client = shallowRef<VmosEdgeClient | null>(null);
const hostIp = ref("192.168.10.50"); // Host IP
const deviceName = ref("EDGE00M7EHBKZGVN"); // Device name
// API response type definitions
interface DeviceInfo {
ip: string;
host_ip: string;
db_id: string;
network_mode: string;
is_macvlan: boolean;
tcp_port: number;
tcp_control_port: number;
}
interface ApiResponse {
code: number;
msg: string;
data: {
count: number;
host_ip: string;
list: DeviceInfo[];
};
}
// Get device information and build configuration
const getDeviceConfig = async (
hostIp: string,
deviceName: string
): Promise<VmosEdgeClientConfig> => {
const response = await fetch(`http://${hostIp}:18182/container_api/v1/get_db`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name: deviceName }),
});
const result: ApiResponse = await response.json();
if (result.code !== 200 || !result.data.list || result.data.list.length === 0) {
throw new Error(result.msg || "Failed to get device information");
}
const device = result.data.list[0];
const isMacvlan = device.network_mode === "macvlan" || device.is_macvlan;
// Build configuration based on network mode
if (isMacvlan) {
// LAN mode (macvlan)
return {
ip: device.ip, // Use device's ip field
deviceId: device.db_id, // Use device's db_id field
ports: {
video: 9999, // LAN mode fixed port
touch: 9997, // LAN mode fixed port
},
};
} else {
// Non-LAN mode (bridge)
return {
ip: result.data.host_ip, // Use host_ip field from data level
deviceId: device.db_id, // Use device's db_id field
ports: {
video: device.tcp_port, // Use device's tcp_port field
touch: device.tcp_control_port, // Use device's tcp_control_port field
},
};
}
};
const connect = async () => {
if (!containerRef.value) return;
// Environment detection
if (!VmosEdgeClient.isWebCodecsSupported()) {
console.error("Current environment does not support SDK usage. Please open the HTML file using file:// protocol");
return;
}
try {
// Get device configuration
const config = await getDeviceConfig(hostIp.value, deviceName.value);
const instance = new VmosEdgeClient({
container: containerRef.value,
config,
retryCount: 3,
});
// Use markRaw to avoid Vue reactive proxy
client.value = markRaw(instance);
// Listen to events
client.value.on(VmosEdgeClientEvents.STARTED, () => {
console.log("Connected successfully");
});
client.value.on(VmosEdgeClientEvents.ERROR, (error: VmosEdgeErrorEvent) => {
console.error("Error:", error);
});
await client.value.start();
} catch (error) {
console.error("Connection failed:", error);
}
};
const disconnect = () => {
client.value?.stop();
client.value = null;
};
const handleHome = () => {
client.value?.home();
};
const handleBack = () => {
client.value?.back();
};
onUnmounted(() => {
disconnect();
});
</script>
<style scoped>
.app-container {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 60px;
padding: 40px;
height: 100vh;
overflow: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background: #fff;
}
.device-container {
width: 360px;
height: 720px;
background: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
flex-shrink: 0;
overflow: hidden;
}
.controls {
display: flex;
flex-direction: column;
gap: 20px;
width: 320px;
flex-shrink: 0;
max-height: 100vh;
overflow: visible;
}
.input-group {
display: flex;
flex-direction: column;
gap: 12px;
}
.label {
font-size: 14px;
font-weight: 500;
color: #333;
margin-bottom: 0;
}
.input {
padding: 12px 16px;
border: 1px solid #e0e0e0;
border-radius: 6px;
font-size: 14px;
transition: all 0.2s;
outline: none;
width: 100%;
background: #fff;
}
.input:focus {
border-color: #4a90e2;
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
}
.button-group {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.btn {
padding: 12px 20px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
outline: none;
min-width: 0;
}
.btn-primary {
background: #4a90e2;
color: white;
grid-column: 1 / -1;
}
.btn-primary:hover {
background: #357abd;
}
.btn-secondary {
background: #6c757d;
color: white;
}
.btn-secondary:hover {
background: #5a6268;
}
.btn-action {
background: #f8f9fa;
color: #333;
border: 1px solid #dee2e6;
}
.btn-action:hover {
background: #e9ecef;
}
</style>
import { useEffect, useRef, useState } from "react";
import {
VmosEdgeClient,
VmosEdgeClientEvents,
type VmosEdgeClientConfig,
type VmosEdgeErrorEvent,
} from "@vmosedge/web-sdk";
// API response type definitions
interface DeviceInfo {
ip: string;
host_ip: string;
db_id: string;
network_mode: string;
is_macvlan: boolean;
tcp_port: number;
tcp_control_port: number;
}
interface ApiResponse {
code: number;
msg: string;
data: {
count: number;
host_ip: string;
list: DeviceInfo[];
};
}
function App() {
const containerRef = useRef<HTMLDivElement>(null);
const clientRef = useRef<VmosEdgeClient | null>(null);
const [connected, setConnected] = useState(false);
const [hostIp, setHostIp] = useState("192.168.10.50"); // Host IP
const [deviceName, setDeviceName] = useState("EDGE00M7EHBKZGVN"); // Device name
// Get device information and build configuration
const getDeviceConfig = async (
hostIp: string,
deviceName: string
): Promise<VmosEdgeClientConfig> => {
const response = await fetch(`http://${hostIp}:18182/container_api/v1/get_db`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name: deviceName }),
});
const result: ApiResponse = await response.json();
if (result.code !== 200 || !result.data.list || result.data.list.length === 0) {
throw new Error(result.msg || "Failed to get device information");
}
const device = result.data.list[0];
const isMacvlan = device.network_mode === "macvlan" || device.is_macvlan;
// Build configuration based on network mode
if (isMacvlan) {
// LAN mode (macvlan)
return {
ip: device.ip, // Use device's ip field
deviceId: device.db_id, // Use device's db_id field
ports: {
video: 9999, // LAN mode fixed port
touch: 9997, // LAN mode fixed port
},
};
} else {
// Non-LAN mode (bridge)
return {
ip: result.data.host_ip, // Use host_ip field from data level
deviceId: device.db_id, // Use device's db_id field
ports: {
video: device.tcp_port, // Use device's tcp_port field
touch: device.tcp_control_port, // Use device's tcp_control_port field
},
};
}
};
const connect = async () => {
if (!containerRef.current) return;
// Environment detection
if (!VmosEdgeClient.isWebCodecsSupported()) {
console.error("Current environment does not support SDK usage. Please open the HTML file using file:// protocol, or access through localhost");
return;
}
try {
// Get device configuration
const config = await getDeviceConfig(hostIp, deviceName);
const client = new VmosEdgeClient({
container: containerRef.current,
config,
retryCount: 3,
});
clientRef.current = client;
client.on(VmosEdgeClientEvents.STARTED, () => {
setConnected(true);
console.log("Connected successfully");
});
client.on(VmosEdgeClientEvents.ERROR, (error: VmosEdgeErrorEvent) => {
console.error("Error:", error);
});
await client.start();
} catch (error) {
console.error("Connection failed:", error);
}
};
const disconnect = () => {
clientRef.current?.stop();
clientRef.current = null;
setConnected(false);
};
useEffect(() => {
return () => {
disconnect();
};
}, []);
return (
<div style={styles.container}>
<div ref={containerRef} style={styles.deviceContainer} />
<div style={styles.controls}>
<div style={styles.inputGroup}>
<label style={styles.label}>Host IP:</label>
<input
value={hostIp}
onChange={(e) => setHostIp(e.target.value)}
placeholder="e.g., 192.168.10.50"
style={styles.input}
/>
<label style={styles.label}>Device Name:</label>
<input
value={deviceName}
onChange={(e) => setDeviceName(e.target.value)}
placeholder="e.g., EDGE00M7EHBKZGVN"
style={styles.input}
/>
</div>
<div style={styles.buttonGroup}>
<button onClick={connect} style={{ ...styles.btn, ...styles.btnPrimary }}>
Connect
</button>
<button onClick={disconnect} style={{ ...styles.btn, ...styles.btnSecondary }}>
Disconnect
</button>
<button onClick={() => clientRef.current?.home()} style={{ ...styles.btn, ...styles.btnAction }}>
Home
</button>
<button onClick={() => clientRef.current?.back()} style={{ ...styles.btn, ...styles.btnAction }}>
Back
</button>
</div>
</div>
</div>
);
}
const styles = {
container: {
display: "flex",
flexDirection: "row" as const,
alignItems: "center",
justifyContent: "center",
gap: "40px",
padding: "20px",
minHeight: "100vh",
maxHeight: "100vh",
overflow: "hidden",
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
},
deviceContainer: {
width: 360,
height: 720,
background: "#fff",
display: "flex",
justifyContent: "center",
alignItems: "center",
borderRadius: "12px",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
flexShrink: 0,
overflow: "hidden",
},
controls: {
display: "flex",
flexDirection: "column" as const,
gap: "16px",
width: "360px",
flexShrink: 0,
},
inputGroup: {
display: "flex",
flexDirection: "column" as const,
gap: "8px",
},
label: {
fontSize: "14px",
fontWeight: 500,
color: "#333",
marginBottom: "4px",
},
input: {
padding: "12px 16px",
border: "1px solid #e0e0e0",
borderRadius: "6px",
fontSize: "14px",
transition: "all 0.2s",
outline: "none",
},
buttonGroup: {
display: "flex",
gap: "8px",
flexWrap: "wrap" as const,
},
btn: {
padding: "10px 20px",
border: "none",
borderRadius: "6px",
fontSize: "14px",
fontWeight: 500,
cursor: "pointer",
transition: "all 0.2s",
outline: "none",
},
btnPrimary: {
background: "#4a90e2",
color: "white",
flex: 1,
},
btnSecondary: {
background: "#6c757d",
color: "white",
flex: 1,
},
btnAction: {
background: "#f8f9fa",
color: "#333",
border: "1px solid #dee2e6",
},
};
export default App;
<!DOCTYPE html>
<html>
<head>
<title>Vmos Edge Web SDK Example</title>
<style>
* {
box-sizing: border-box;
}
html, body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
body {
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 40px;
min-height: 100vh;
max-height: 100vh;
background: #f5f5f5;
}
#container {
width: 360px;
height: 720px;
background: #fff;
display: flex;
justify-content: center;
align-items: center;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
flex-shrink: 0;
overflow: hidden;
}
.controls {
display: flex;
flex-direction: column;
gap: 16px;
width: 360px;
flex-shrink: 0;
}
.input-group {
display: flex;
flex-direction: column;
gap: 8px;
}
.input-group label {
font-size: 14px;
font-weight: 500;
color: #333;
margin-bottom: 4px;
}
.input-group input {
padding: 12px 16px;
border: 1px solid #e0e0e0;
border-radius: 6px;
font-size: 14px;
transition: all 0.2s;
outline: none;
}
.input-group input:focus {
border-color: #4a90e2;
box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
}
.button-group {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.button-group button {
padding: 10px 20px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
outline: none;
}
.button-group button:hover {
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.btn-primary {
background: #4a90e2;
color: white;
flex: 1;
}
.btn-primary:hover {
background: #357abd;
}
.btn-secondary {
background: #6c757d;
color: white;
flex: 1;
}
.btn-secondary:hover {
background: #5a6268;
}
.btn-action {
background: #f8f9fa;
color: #333;
border: 1px solid #dee2e6;
}
.btn-action:hover {
background: #e9ecef;
}
</style>
</head>
<body>
<div id="container"></div>
<div class="controls">
<div class="input-group">
<label>Host IP:</label>
<input id="hostIp" type="text" placeholder="e.g., 192.168.10.50" value="192.168.10.50" />
<label>Device Name:</label>
<input id="deviceName" type="text" placeholder="e.g., EDGE00M7EHBKZGVN" value="EDGE00M7EHBKZGVN" />
</div>
<div class="button-group">
<button onclick="connect()" class="btn-primary">Connect</button>
<button onclick="disconnect()" class="btn-secondary">Disconnect</button>
<button onclick="handleHome()" class="btn-action">Home</button>
<button onclick="handleBack()" class="btn-action">Back</button>
</div>
</div>
<script type="module">
import {
VmosEdgeClient,
VmosEdgeClientEvents,
} from "@vmosedge/web-sdk";
let client = null;
// Get device information and build configuration
async function getDeviceConfig(hostIp, deviceName) {
const response = await fetch(`http://${hostIp}:18182/container_api/v1/get_db`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name: deviceName }),
});
const result = await response.json();
if (result.code !== 200 || !result.data.list || result.data.list.length === 0) {
throw new Error(result.msg || "Failed to get device information");
}
const device = result.data.list[0];
const isMacvlan = device.network_mode === "macvlan" || device.is_macvlan;
// Build configuration based on network mode
if (isMacvlan) {
// LAN mode (macvlan)
return {
ip: device.ip, // Use device's ip field
deviceId: device.db_id, // Use device's db_id field
ports: {
video: 9999, // LAN mode fixed port
touch: 9997, // LAN mode fixed port
},
};
} else {
// Non-LAN mode (bridge)
return {
ip: result.data.host_ip, // Use host_ip field from data level
deviceId: device.db_id, // Use device's db_id field
ports: {
video: device.tcp_port, // Use device's tcp_port field
touch: device.tcp_control_port, // Use device's tcp_control_port field
},
};
}
}
async function connect() {
const container = document.getElementById("container");
const hostIp = document.getElementById("hostIp").value;
const deviceName = document.getElementById("deviceName").value;
// Environment detection
if (!VmosEdgeClient.isWebCodecsSupported()) {
console.error("Current environment does not support SDK usage. Please open the HTML file using file:// protocol, or access through localhost");
return;
}
try {
// Get device configuration
const config = await getDeviceConfig(hostIp, deviceName);
client = new VmosEdgeClient({
container,
config,
retryCount: 3,
});
client.on(VmosEdgeClientEvents.STARTED, () => {
console.log("Connected successfully");
});
client.on(VmosEdgeClientEvents.ERROR, (error) => {
console.error("Error:", error);
});
await client.start();
} catch (error) {
console.error("Connection failed:", error);
}
}
function disconnect() {
if (client) {
client.stop();
client = null;
}
}
function handleHome() {
client?.home();
}
function handleBack() {
client?.back();
}
// Export to global scope
window.connect = connect;
window.disconnect = disconnect;
window.handleHome = handleHome;
window.handleBack = handleBack;
</script>
</body>
</html>
:::
⚠️ Important Notes
Vue/React Framework Usage
Important: When using in Vue or React, VmosEdgeClient instances should NOT be deeply proxied.
- Vue 3: Use
shallowRefandmarkRaw - React: Use
useRef
Wrong Example (Vue):
// ❌ Wrong: Using ref will cause Proxy proxy issues
const client = ref<VmosEdgeClient | null>(null);
client.value = new VmosEdgeClient({ /* ... */ });
Correct Example (Vue):
// ✅ Correct: Use shallowRef and markRaw
const client = shallowRef<VmosEdgeClient | null>(null);
const instance = new VmosEdgeClient({ /* ... */ });
client.value = markRaw(instance);
Container Element
- Container element must be a valid
HTMLElement - SDK will create a
.vmos-canvas-containerelement inside the container - It's recommended to set fixed dimensions for the container to avoid layout issues
Connection Configuration
- Single Control Mode: Both
videoandtouchports are required - Group Control Mode: Slave devices only need
touchport,videoport is not required audioport is not supported, do not configure it- Ensure device IP and port configuration are correct
Error Handling
- Always listen to
ERRORevents and handle connection errors promptly - Handle accordingly based on error type (
error.type) and error code (error.code)
Resource Cleanup
- Always call
client.stop()to release resources when components unmount or pages close - Avoid memory leaks

