Skip to main content

Vue Compact Call Tutorial

Build a Vue 3 compact call with mediasfu-vue@1.3.0: 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-room and /api/mediasfu/join-room routes.

Project files​

package.json
{"private":true,"scripts":{"dev":"vite"},"dependencies":{"mediasfu-vue":"1.3.0","vue":"3.5.13"},"devDependencies":{"@vitejs/plugin-vue":"5.2.1","typescript":"5.9.3","vite":"5.4.19"}}
src/room-gateway.ts
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);
src/App.vue
<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>
src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
index.html
<!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>
vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({ plugins: [vue()], server: { proxy: { '/api': 'http://localhost:8787' } } });
tsconfig.json
{"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. To end the room for everyone as host, see Leave, end, and rejoin.

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.