Skip to main content

Add a “video call us” button to your website

The fastest path from visitor on your site to face-to-face video session is the OrbitVideoRoom prebuilt widget — the drop-in, embeddable video-call UI in the Web SDK. You ship one script tag plus three lines of JavaScript, and the widget paints a complete conferencing surface with nothing else to build:
  • a participant tile grid and local self-view
  • a control bar with mute, camera, screen-share, a device picker (microphone / camera / speaker, switchable mid-call), background blur, and leave
  • automatic attach of remote tracks as they are subscribed
This guide is the end-to-end walkthrough of the pattern operators run as a “video call us” or “video consultation” button: the visitor’s browser loads the widget, your backend hands it a one-shot join token, the join lands in an optional waiting room until an agent (host) admits them, and the session recording lives on your storage under a tenant-controlled retention window.

The four moving parts

1 — Embed the button on your site

The widget is host-agnostic — it renders into whatever container element you pass. Mount it behind a click so the media session only starts when the visitor actually asks for it.
The full config surface — startWithCamera, startWithMicrophone, enableScreenShare, enableDeviceSelection, autoJoin: false, the participantJoined / participantLeft / error event map, and the join() / leave() lifecycle — is on the Web SDK page under Prebuilt video room.

2 — Mint the join token on your backend (never in the browser)

Your API key must never reach the visitor’s browser. The token comes from the same route the video-meetings guide uses — POST /api/v1/video/rooms/:id/join — issued by your backend, which then hands only the short-lived token and the media-server URL to the page.
The response carries token (the media-server access JWT) and livekit_url (the orbit-media WebSocket URL — point the widget at this host, not at the retired livekit.cloud). Because your backend mints it per click, each visitor gets a fresh, scoped token and your long-lived API key stays server-side. For a consultation you usually want one persistent room per queue or department (“the sales room”, “the support room”) rather than a new room per visitor: create it once from the dashboard (Rooms → New room) or the video rooms API, then have your backend mint join tokens against that same room ID.

3 — Put a waiting room in front of your agents

A consultation button that rings agents blindly is a poor experience. Arm the room’s waiting room so a new join holds in a receive-only lobby until a host admit — the same hold-and-admit flow the video-meetings surface uses for drop-in guests. The join route documents this in its response contract: the participant_tier and permissions fields are the effective grant after any waiting-room clamp, and lobby_downgraded is true when an armed waiting room forced this join to receive-only viewer. Your cue is simple:
  • permissions.can_publish === false && permissions.can_subscribe === false → the visitor is in the lobby; render “waiting for the team to admit you”
  • on admit, the host promotes them from the roster and their publish grant activates
From the dashboard, an agent opens the same room, sees the lobby in the host moderation panel, and admits the visitor — so the agent surface needs nothing new.

4 — Record the session and set its retention

Consultation sessions are usually recorded for quality or compliance. Enable recording_enabled on the room (dashboard settings or the rooms API) and the session records to your tenant’s configured storage, with signed download URLs — the same per-tenant storage posture the rest of the recording stack uses. Retention is a tenant-config window, not a platform lock-up. The hourly retention sweep reads organizations.settings.video_room_retention_days:
  • Default — 90 days. Sessions whose ended_at is older than the window are soft-deleted; after a further 14-day grace they are hard-deleted.
  • Tenant override — set video_room_retention_days to a positive integer (minimum 7 days) to lengthen or shorten the window for your own compliance posture, or to lengthen the window for sessions you must keep.

Why not livekit.cloud?

Everything on this page runs on Orbit’s self-hosted media stack (orbit-media). The token’s livekit_url is an orbit-media host — that field name is inherited from the upstream fork; the actual media path is Orbit’s own, which is why livekit.cloud (retired 2026-05-19) never appears here. Self-hosting the media path is also why the embed adds no outbound voice/SMS provider — the consultation is inbound WebRTC video end to end.

Production checklist

  • The join token is minted server-side; the API key is never in the page.
  • serverUrl points at the livekit_url from the join response (an orbit-media host).
  • The button only mounts the widget on click, so idle page loads cost nothing.
  • waiting_room: true on the room, and your agents admit from the host moderation panel.
  • recording_enabled is set for sessions you must keep.
  • video_room_retention_days matches your compliance window (or you accept the 90-day default).
  • You re-mint the token before expires_at if a session can run long.