SDK JavaScript (@videochamada/embed)
O SDK oficial @videochamada/embed permite incorporar uma videochamada na sua própria
aplicação e montar a interface com a sua cara — escondendo os controles nativos e
comandando tudo (microfone, câmera, tela, chat, layout, encerrar) por JavaScript.
É um wrapper fino e tipado sobre o protocolo iframe + postMessage descrito em
Controle Embed. Use o SDK para não precisar escrever postMessage na mão.
Como se encaixa
- White-label visual (cor e logo da sua marca por projeto) e domínio personalizado continuam valendo — veja Personalização de URLs.
- A criação da chamada acontece no seu backend via
POST /api/callscom a sua API Key. O SDK cuida só da interface no navegador.
Instalação
Ou direto no navegador via um CDN de ES modules:
<script type="module">
import { VideochamadaCall } from 'https://esm.sh/@videochamada/embed';
// ...
</script>
Início rápido
import { VideochamadaCall } from '@videochamada/embed';
const call = new VideochamadaCall({
container: '#video', // seletor CSS ou elemento
baseUrl: 'https://sua-org.videochamada.com.br', // subdomínio da org OU domínio próprio
callId: 'abc-123', // vindo de POST /api/calls
username: 'Maria',
hideControls: true, // esconde nossos controles: você desenha os seus
});
// eventos da chamada
call.on('ready', () => console.log('iframe carregado'));
call.on('participantJoined', (p) => console.log('entrou:', p));
call.on('participantLeft', (p) => console.log('saiu:', p));
call.on('callEnded', (info) => console.log('encerrou:', info));
call.on('status', (s) => console.log('status:', s));
// os seus botões
botaoMic.onclick = () => call.toggleAudio();
botaoCam.onclick = () => call.toggleVideo();
botaoTela.onclick = () => call.toggleScreenShare();
botaoSair.onclick = () => call.endCall();
Fluxo completo
1. Backend: POST https://api.videochamada.com.br/api/calls
Authorization: Bearer SUA_API_KEY -> { id: "abc-123", ... }
2. Backend devolve o callId para o navegador.
3. Front: new VideochamadaCall({ callId, baseUrl, container, hideControls: true })
4. Você renderiza a sua UI e comanda a chamada pelos métodos abaixo.
Opções do construtor
| Opção | Tipo | Padrão | Descrição |
|---|---|---|---|
container |
string \| HTMLElement |
— | Onde montar o iframe. Obrigatório. |
baseUrl |
string |
— | Origem do seu projeto (subdomínio da org ou domínio próprio). Obrigatório. |
callId |
string |
— | Id da chamada (de POST /api/calls). Obrigatório. |
username |
string |
— | Pré-preenche o nome do participante. |
userId |
string |
— | Id estável do participante. |
hideControls |
boolean |
false |
Atalho para features.controlBar = false. |
features |
object |
{} |
Desliga recursos individualmente (só false tem efeito). |
width / height |
number \| string |
100% |
Tamanho do iframe (número = px). |
allow |
string |
camera; microphone; display-capture; autoplay; fullscreen |
Atributo allow do iframe. |
features aceita: chat, clock, controlBar, closeButton, raiseHand, screenShare,
recording, transcription, virtualBackground, hardwareTest, pendingCallCard,
nameInput, waitingRoom, summary.
Recursos são disable-only
As flags só desligam recursos. Se um recurso já estiver desativado no painel do projeto, a URL/SDK não consegue religá-lo — a configuração do painel sempre vence.
Métodos
| Método | Ação |
|---|---|
toggleAudio() / mute() / unmute() |
Microfone |
toggleVideo() / enableCamera() / disableCamera() |
Câmera |
toggleScreenShare() / startScreenShare() / stopScreenShare() |
Compartilhar tela |
openChat() / closeChat() / toggleChat() |
Chat |
toggleRaiseHand() |
Levantar a mão |
setLayout('mosaic' \| 'sidebar') |
Trocar o layout direto |
openLayoutDialog() |
Abrir o seletor de layout |
openSettings() |
Abrir configurações de dispositivos |
toggleConnectionStatus() |
Mostrar/ocultar status de conexão |
endCall() |
Encerrar a chamada |
getStatus(timeoutMs?) |
Promise<CallStatus> com o status atual |
destroy() |
Remove o iframe e desliga os listeners |
Eventos
Assine com call.on(evento, handler) — retorna uma função para cancelar a assinatura.
| Evento | Payload |
|---|---|
ready |
— (iframe carregou) |
status |
CallStatus |
audioToggled |
{ enabled } |
videoToggled |
{ enabled } |
screenShareToggled |
{ enabled } |
participantJoined |
{ participantId, name } |
participantLeft |
{ participantId } |
callEnded |
{ reason } |
CallStatus: { audioEnabled, videoEnabled, screenShareEnabled, chatOpen, handRaised, layoutMode, participantCount, isRecording, connectionStatusVisible }.
Tema / white-label (deixar a chamada com a sua cara)
Passe um theme para restilizar a chamada por dentro — fundo, barra de
controles, botões, tiles de vídeo, cantos e fonte — sem tocar na nossa marcação
interna. Requer @videochamada/embed ≥ 0.2.0.
const call = new VideochamadaCall({
container: '#video', baseUrl, callId, hideControls: true,
theme: {
background: '#0b1220',
controlBarBackground: '#111a2e',
buttonBackground: '#0ea5a4',
buttonText: '#04121a',
accent: '#0ea5a4',
endCallBackground: '#e11d48',
tileBackground: '#0f172a',
tileRadius: '18px',
textColor: '#e6edf7',
font: 'Inter, sans-serif',
},
});
// trocar em tempo real:
call.setTheme({ accent: '#9333ea', controlBarBackground: '#1e1b4b' });
Tokens disponíveis
| Token | Aplica em |
|---|---|
background |
Fundo da área de vídeo |
surface |
Painéis (chat, diálogos) |
controlBarBackground |
Barra de controles |
buttonBackground / buttonText |
Botões de controle |
accent |
Cor de destaque + paleta primária (chat, sala de espera) |
endCallBackground |
Botão de encerrar |
tileBackground / tileRadius |
Fundo e cantos dos tiles de vídeo |
textColor |
Nome do participante |
font |
Fonte |
Seguro por padrão
Todos os campos são opcionais — o que você não passar mantém o visual padrão.
Só valores CSS seguros são aceitos (o app rejeita url(), @import e
caracteres que quebrariam a regra). A estilização é aplicada por dentro do
iframe pelo próprio app (o navegador não deixa o site pai injetar CSS num
iframe de outro domínio).
Exemplo com React
import { useEffect, useRef, useState } from 'react';
import { VideochamadaCall } from '@videochamada/embed';
export function Call({ baseUrl, callId, username }) {
const box = useRef(null);
const call = useRef(null);
const [status, setStatus] = useState({});
useEffect(() => {
const c = new VideochamadaCall({ container: box.current, baseUrl, callId, username, hideControls: true });
c.on('status', setStatus);
call.current = c;
return () => c.destroy(); // limpa o iframe + listeners
}, [baseUrl, callId, username]);
return (
<div>
<div ref={box} style={{ aspectRatio: '16 / 9' }} />
<button onClick={() => call.current.toggleAudio()}>
{status.audioEnabled === false ? 'Ativar microfone' : 'Mutar'}
</button>
<button onClick={() => call.current.toggleVideo()}>Câmera</button>
<button onClick={() => call.current.endCall()}>Encerrar</button>
</div>
);
}
Segurança
- O SDK só aceita mensagens vindas da origem de
baseUrle envia comandos apenas para essa origem. - Mantenha a sua API Key no backend. Nunca a exponha no código do navegador — o front só
precisa do
callId.
Solução de problemas
| Sintoma | Causa provável | O que fazer |
|---|---|---|
| Os eventos nunca disparam | baseUrl diferente do domínio real do iframe |
Use exatamente o subdomínio da org (ou o domínio personalizado). A checagem de origem descarta mensagens de outra origem. |
| Câmera/microfone não ligam | Permissão do navegador negada | O usuário precisa permitir câmera/microfone; o iframe já pede via allow. Em https apenas. |
Um recurso não aparece mesmo passando features |
Ele está desligado no painel do projeto | As flags são disable-only — o painel vence. Reative pelo painel. |
getStatus() dá timeout |
Iframe ainda não carregou | Chame após o evento ready, ou aumente o timeoutMs. |
| Iframe em branco | callId inválido/expirado |
Gere um novo callId em POST /api/calls. |