# JavaScript APIs

Source: https://www.veeting.com/en/developer-documentation/javascript-apis

## Overview

The JavaScript API lets your own page drive a running meeting room: mute a participant, read the participants list, send chat messages, change devices, listen for events. It works whether you embed the room as an iFrame or use the Veeting Blocks web components.

## Where your code runs determines how you reach the API

This choice matters more than anything else on this page, so settle it first.

| Your code runs                                                                | How you reach the API                                                                             |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| **Inside the meeting room**, which means Veeting Blocks or a custom tool page | Directly, through the handler. You get the full API, including return values.                     |
| **In the page around an embedded iFrame**                                     | Through `postMessage`. You can call any method that returns nothing, and you receive every event. |

If you embed the room in an iFrame, your page and the meeting room are two different documents, usually on two different origins. Your page cannot reach into the room's `window`, and the room cannot reach into yours. Everything crosses that boundary as a message.

**Cross-origin is expected and supported.** The room normally runs on your own white-label domain, such as `meeting.example.com`, while your application sits on `app.example.com` or somewhere else entirely. Neither case needs anything special: a different subdomain and a completely different domain behave the same way here.

## Driving the room from the page around it

### Receiving events

The meeting room posts every event to its parent window. Listen for those messages:

```javascript
window.addEventListener("message", (message) => {
  // Always check the origin. The room posts to any parent, so this check is
  // yours to make, and without it any page could forge these events.
  if (message.origin !== "https://<DOMAIN-NAME>") {
    return;
  }

  const { event, payload } = message.data;

  if (event === "joined") {
    console.log("The meeting room is ready");
  }

  if (event === "participantsUpdated") {
    console.log(`${payload.length} participants in the room`);
  }
});
```

The `event` is one of the twelve names below, and `payload` is exactly what that event carries. You do not have to subscribe: every event is posted to the parent whether you listen or not.

### Calling methods

Post a message to the iFrame that names the method and its arguments:

```javascript
const room = document.getElementById("meeting-frame");

room.contentWindow.postMessage({
  action: "muteAudio",
  payload: [true]
}, "https://<DOMAIN-NAME>");
```

`action` is the method name, and `payload` holds its arguments in order, as an array. For a method that takes no arguments, pass `payload: []` or leave it out.

Because messaging across the boundary is one-way, two limits apply:

- **You get no return value.** Anything beginning with `get` is therefore not useful across the boundary. Read the participants from the `participantsUpdated` event instead of calling `getParticipantsList()`, and take the room configuration from `meetingRoomConfigUpdated`.
- **You get no error either.** If you misspell the method name, nothing happens and nothing is reported. Check the name against the tables below.

### A complete example

A mute button and participant counter in your own page, outside the iFrame:

```html
<button id="mute">Mute</button>
<span id="count">0</span> participants

<iframe id="meeting-frame"
  src="https://<DOMAIN-NAME>/meeting/<MEETING-ID>"
  allow="microphone;camera;encrypted-media;fullscreen;autoplay;display-capture;layout-animations;">
</iframe>

<script>
  const ROOM_ORIGIN = "https://<DOMAIN-NAME>";
  const room = document.getElementById("meeting-frame");
  let muted = false;

  window.addEventListener("message", (message) => {
    if (message.origin !== ROOM_ORIGIN) {
      return;
    }
    if (message.data.event === "participantsUpdated") {
      document.getElementById("count").textContent = message.data.payload.length;
    }
  });

  document.getElementById("mute").addEventListener("click", () => {
    muted = !muted;
    room.contentWindow.postMessage({ action: "muteAudio", payload: [muted] }, ROOM_ORIGIN);
  });
</script>
```

## Getting the handler

The rest of this section applies to code running **inside** the meeting room: Veeting Blocks or a custom tool. If you are embedding an iFrame, use the messages above instead.

The API only exists once the meeting room has finished loading, so you cannot call it from a script that runs at page load. Instead, define a `wlvmrApiReady` function on `window`. The meeting room calls that function when it is ready and passes the name of the object it registered itself under.

```javascript
window["wlvmrApiReady"] = (handler) => {
  if (!window[handler]) {
    console.error(`Handler window.${handler} not found!`);
    return;
  }

  // Every API method lives on this object
  window[handler].muteAudio(true);
};
```

Two rules follow, and both trip people up:

1. **Define `wlvmrApiReady` before the meeting room loads.** If you assign it afterward, the call has already happened and you never receive the handler.
2. **Do not hard-code the handler name.** The meeting room passes it to you as an argument. Always use `window[handler]`, never a literal.

## A worked example

Waiting for the room, subscribing to events, then calling methods:

```javascript
window["wlvmrApiReady"] = (handler) => {
  if (!window[handler]) {
    console.error(`Handler window.${handler} not found!`);
    return;
  }

  const api = window[handler];

  api.on("joined", () => {
    console.log("The meeting room is ready to use");
  });

  api.on("participantsUpdated", (participants) => {
    console.log(`${participants.length} participants in the room`);
  });

  api.on("chatMessage", (message) => {
    console.log(`${message.fromParticipantName}: ${message.message}`);
  });

  api.setAudioInputDeviceId("default", false);
  api.setVideoInputDeviceId("default", true);
};
```

## Events

Subscribe with `on(event, callback)`. There are twelve events.

| Event                      | Fires when                                                 | Payload                   |
| -------------------------- | ---------------------------------------------------------- | ------------------------- |
| `beforeConnecting`         | Just before the room connects its media                    | none                      |
| `connected`                | The websocket to the Veeting API is established and in use | none                      |
| `joined`                   | The meeting room is ready to use                           | none                      |
| `disconnected`             | The websocket to the Veeting API is disconnected or unused | none                      |
| `leave`                    | The participant leaves the meeting                         | none                      |
| `participantsUpdated`      | Somebody joins, leaves, or changes state                   | `IApiParticipant[]`       |
| `chatMessage`              | A group chat message arrives                               | `IApiChatMessage`         |
| `privateChatMessage`       | A private chat message arrives                             | `IApiChatMessage`         |
| `meetingDurationUpdated`   | The remaining meeting time changes                         | `IApiRemainingTimeUpdate` |
| `meetingRoomConfigUpdated` | The room configuration changes                             | `IMeetingRoomConfig`      |
| `customMessage`            | Another participant sends a custom message                 | `ICustomMessage`          |
| `screenshareStateChange`   | Screen sharing starts or stops                             | `IScreenshareState`       |

> **Note:** `connected` and `disconnected` describe the websocket to our API, not the WebRTC media. A participant can be disconnected from media and still use the whiteboard.

## Methods

### Meeting and participants

| Method                                     | Description                                              |
| ------------------------------------------ | -------------------------------------------------------- |
| `getVersion(): string`                     | The version string of the running meeting room.          |
| `getParticipantsList(): IApiParticipant[]` | The current participants list.                           |
| `leaveMeeting(): void`                     | Disconnects from the server and leaves the meeting room. |
| `enableFollowMe(enabled: boolean): void`   | Enables Follow Me. Requires moderator rights.            |

### Audio and video

| Method                                                            | Description                                                                                               |
| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `muteAudio(muted: boolean): void`                                 | Mutes or unmutes audio.                                                                                   |
| `toggleMuteAudio(): void`                                         | Toggles audio mute.                                                                                       |
| `muteVideo(muted: boolean): void`                                 | Mutes or unmutes video.                                                                                   |
| `toggleMuteVideo(): void`                                         | Toggles video mute.                                                                                       |
| `setVolume(volume: number, meetingParticipantId?: string): void`  | Sets the playback volume for one participant or for everyone.                                             |
| `connect(mediaConfig?: { audio: boolean, video: boolean }): void` | Connects media. Ignored if already connected. Participants connect automatically when they join.          |
| `disconnect(): void`                                              | Disconnects media. Ignored if already disconnected.                                                       |
| `restartMediaConnections(): void`                                 | Restarts the media connections. Useful after a device change.                                             |
| `enterVideoFullscreen(): void`                                    | Enters fullscreen. Fails in most browsers other than Chrome because fullscreen requires user interaction. |

### Devices

| Method                                                                                   | Description                                                                                            |
| ---------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `getMediaDeviceSettings(): IMediaDeviceSettings`                                         | The currently selected devices and resolution.                                                         |
| `getMediaDeviceAudioInputList(audioOnly: boolean): MediaDeviceInfo[]`                    | The available microphones. `audioOnly` limits the permission prompt to audio.                          |
| `getMediaDeviceAudioOutputList(audioOnly: boolean): MediaDeviceInfo[]`                   | The available speakers. `audioOnly` limits the permission prompt to audio.                             |
| `getMediaDeviceVideoInputList(): MediaDeviceInfo[]`                                      | The available cameras.                                                                                 |
| `setAudioInputDeviceId(deviceId: string, reconnect: boolean): void`                      | Sets the microphone. The API does not check that the device ID is valid.                               |
| `setAudioOutputDeviceId(deviceId: string, reconnect: boolean): void`                     | Sets the speaker. Only Chrome and Edge support this today.                                             |
| `setVideoInputDeviceId(deviceId: string, reconnect: boolean): void`                      | Sets the camera. The API does not check that the device ID is valid.                                   |
| `setVideoResolution(resolution: MeetingRoomVideoResolution, reconnect: boolean): void`   | Sets the outgoing video resolution.                                                                    |
| `setMediaStreamConstraints(constraints: MediaStreamConstraints, merge?: boolean): void`  | Constraints for `getUserMedia`. `merge` defaults to `true`, which combines your constraints with ours. |
| `setDisplayMediaConstraints(constraints: MediaStreamConstraints, merge?: boolean): void` | Constraints for `getDisplayMedia`. `merge` defaults to `true`.                                         |

`reconnect` defaults to `false`. Pass `true` to apply the change immediately by reconnecting media.

> **The three list methods can prompt the participant.** They ask the browser for media permission to read device labels, so calling one can open a permission dialog. Call them when the participant expects it, not on page load.

### Screen sharing and recording

| Method                                                    | Description                                                                                                     |
| --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `setScreensharingInterceptor(callback: () => void): void` | Lets an Electron application intercept screen-sharing requests and pre-select a source.                         |
| `startScreensharing(sourceId?: string): void`             | Starts screen sharing, optionally from a given source. Does nothing if the participant is not allowed to share. |
| `stopScreensharing(): void`                               | Stops screen sharing.                                                                                           |
| `forceStopScreensharing(): void`                          | Stops another participant's screen sharing. Moderators only; the server blocks it otherwise.                    |
| `startRecording(): void`                                  | Starts recording. Only works if the meeting is configured for partial recording.                                |
| `stopRecording(): void`                                   | Stops recording. Subject to the same condition.                                                                 |

### Messaging

| Method                                                                 | Description                                                                       |
| ---------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| `sendChatMessage(message: string): void`                               | Sends a group chat message.                                                       |
| `sendPrivateChatMessage(message: string, participantId: string): void` | Sends a private chat message to one participant.                                  |
| `sendCustomMessage(message: ICustomMessage): void`                     | Sends a custom message to all participants, delivered as a `customMessage` event. |

### Layout and events

| Method                                                                 | Description                                                                                                               |
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `setVideoDisplayCalculator(calculator: IVideoDisplayCalculator): void` | Takes over how videos are arranged. See [video display calculator](/en/developer-documentation/video-display-calculator). |
| `on(event: MeetingRoomApiEvent, callback: ApiEventCallback): void`     | Subscribes to an event.                                                                                                   |

## Additional methods in Veeting Blocks

If you are using Veeting Blocks rather than an embedded room, the API offers four more methods for driving the join flow yourself:

| Method                                                         | Description                                               |
| -------------------------------------------------------------- | --------------------------------------------------------- |
| `isBrowserSupported(): boolean`                                | Whether the current browser can run a meeting.            |
| `loadMeeting(meetingId: string): Promise<IMeetingRoomConfig>`  | Loads a meeting's configuration.                          |
| `joinMeeting(config: IMeetingConnectionConfig): Promise<void>` | Joins the meeting.                                        |
| `can(meetingPermission: string): Promise<boolean>`             | Whether the current participant has the given permission. |

## Type definitions

```typescript
interface IApiParticipant {
  id: string;
  name: string;
  muted?: boolean;
  handRaised?: boolean;
  fromPSTN?: boolean;
  hasVideo?: boolean;
  hadVideo?: boolean;
  joinedAt: number;
}

interface IApiChatMessage {
  fromParticipantId: string;
  fromParticipantName: string;
  message: string;
}

interface IApiRemainingTimeUpdate {
  remainingSeconds: number;
}

interface IScreenshareState {
  active: boolean;
}

interface IMediaDeviceSettings {
  videoResolution: string;
  audioInputDeviceId: string;
  audioOutputDeviceId: string;
  videoInputDeviceId: string;
}

interface IMeetingConnectionConfig {
  meetingId: string;
  participantName: string;
  participantEmail?: string;
  audio: boolean;
  video: boolean;
  moderatorToken?: string;
  interpreterToken?: string;
  invisibleToken?: string;
  speakerToken?: string;
}

type MediaDirection = "receiveonly" | "sendonly" | "sendreceive";
type JoinMode = "audio-only" | "audio-video" | "video-only" | "no-media";

type ApiEventCallback = (payload: void | IApiParticipant[] | IApiChatMessage
  | IApiRemainingTimeUpdate | IMeetingRoomConfig | ICustomMessage | IScreenshareState) => void;
```

## Common mistakes

- Assigning `wlvmrApiReady` after the meeting room has loaded, so it is never called.
- Hard-coding the handler name instead of using the one passed to the callback.
- Calling a method before the `joined` event, when the room is loaded but not yet in the meeting.
- Expecting `connected` to mean media is flowing. It refers to the websocket to our API.
- Expecting `startScreensharing` to report a problem. If the participant is not allowed to share, it returns silently.
- Calling `startRecording` on a meeting that is not configured for partial recording.
- Calling `forceStopScreensharing` as a non-moderator. The server blocks it.
- Passing a device ID without checking that it exists. The API does not validate it.

---

## The rest of this documentation

- [Custom tools](https://www.veeting.com/en/developer-documentation/custom-tools)
- [External meeting authorization service](https://www.veeting.com/en/developer-documentation/external-meeting-authorization-service)
- [iFrame and Web Components](https://www.veeting.com/en/developer-documentation/iframe-and-web-components)
- [Query parameters](https://www.veeting.com/en/developer-documentation/query-parameters)
- [Veeting Blocks - Components](https://www.veeting.com/en/veeting-blocks/components)
- [Veeting Blocks - Introduction](https://www.veeting.com/en/veeting-blocks/introduction)
- [Veeting Blocks - JavaScript and Typescript APIs](https://www.veeting.com/en/veeting-blocks/apis)
- [Veeting Rooms REST APIs](https://www.veeting.com/en/developer-documentation/api-usage)
- [Video display calculator](https://www.veeting.com/en/developer-documentation/video-display-calculator)
- [Web hooks](https://www.veeting.com/en/developer-documentation/web-hooks)

All of it in one file: https://www.veeting.com/llms-full.txt
