Vue Compact Call Tutorial
Build a Vue 3 compact call with mediasfu-vue@1.1.1: secure create and join,
participants, microphone, camera, remote media, screen sharing, and leave.
Prerequisites
- Node.js 18 to 20, Vue 3, and HTTPS or
localhost. - Two browser profiles for the final call test.
- Authenticated
/api/mediasfu/create-roomand/api/mediasfu/join-roomroutes.
Project files
{"private":true,"scripts":{"dev":"vite"},"dependencies":{"mediasfu-vue":"1.1.1","vue":"3.5.13"},"devDependencies":{"@vitejs/plugin-vue":"5.2.1","typescript":"5.9.3","vite":"5.4.19"}}
import type { CreateJoinRoomResult, CreateRoomOnMediaSFUType, JoinRoomOnMediaSFUType } from 'mediasfu-vue';
async function postRoom(url: string, payload: unknown): Promise<CreateJoinRoomResult> {
const response = await fetch(url, { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(payload) });
if (!response.ok) throw new Error(`Room request failed (HTTP ${response.status}).`);
return response.json() as Promise<CreateJoinRoomResult>;
}
export const createRoomViaBackend: CreateRoomOnMediaSFUType = ({ payload }) => postRoom('/api/mediasfu/create-room', payload);
export const joinRoomViaBackend: JoinRoomOnMediaSFUType = ({ payload }) => postRoom('/api/mediasfu/join-room', payload);
<script setup lang="ts">
import { MediasfuGeneric } from 'mediasfu-vue';
import 'mediasfu-vue/dist/mediasfu-vue.css';
import { createRoomViaBackend, joinRoomViaBackend } from './room-gateway';
</script>
<template><MediasfuGeneric :return-u-i="true" :connect-media-s-f-u="true" :create-media-s-f-u-room="createRoomViaBackend" :join-media-s-f-u-room="joinRoomViaBackend" /></template>
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
<!doctype html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>MediaSFU compact call</title></head><body><div id="app"></div><script type="module" src="/src/main.ts"></script></body></html>
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({ plugins: [vue()], server: { proxy: { '/api': 'http://localhost:8787' } } });
{"compilerOptions":{"target":"ES2022","lib":["DOM","DOM.Iterable","ES2022"],"strict":true,"module":"ESNext","moduleResolution":"Bundler","skipLibCheck":true,"isolatedModules":true,"noEmit":true},"include":["src"]}
The supplied MediasfuGeneric renders the first working room. Start with its
supplied controls. For local development, use only a restricted, revocable,
uncommitted credential on the backend. Before distribution, external testing,
or production rooms, reusable Cloud credentials remain only in the authenticated
backend.
Room-authority server
Create the two /api/mediasfu routes with the complete Node + Express example
in the public production room credential boundary.
It keeps MEDIASFU_API_USERNAME and MEDIASFU_API_KEY in server environment
variables and returns only a room result to this browser. For a local test,
replace the route's authentication middleware with your own temporary,
uncommitted app-session check; before external testing or release, use your
application's normal session or JWT middleware. Do not put either MediaSFU
variable in browser configuration.
Run
npm install
npm run dev
Expected result
Create and join with separate browser profiles. Observe both participants, then prove microphone, camera, remote playback, and screen sharing in both directions. Use Leave and confirm that the remaining participant sees departure.
Recovery
Treat access rejection, rate limits, device denial, no device, transport error, paused remote media, autoplay blocking, and display-picker cancellation as separate states. Vue 1.1.1 does not document a separate host-wide end action.
Cleanup
On confirmed leave, remove app listeners, stop app-owned tracks, close app-owned transports, clear UI state, and let the backend expire room authority.