Meeting Observer | Eyeson REST API
Setup
The Meeting Observer provides a one-way WebSocket connection based on the Rails ActionCable protocol, with AnyCable as its successor.
You can connect to any active room that was started using your API key.
Preparations
The connection URL follows this format:
https://api.eyeson.team/rt?room_id=$YOUR_ROOM_ID
Depending on your implementation, you may need to use the wss://
protocol instead of https://
.
Channel subscription
To receive events, subscribe to the channel named RoomChannel
.
The connection automatically closes when the meeting ends.
Authorization
An API key is required to connect. If you don't have one yet, see our guide on obtaining an API key.
You can include your API key in one of three ways:
- As an "Authorization" header
- As a WebSocket protocol parameter
- As a URL query parameter:
api_key=YOUR_API_KEY
The method you choose depends on your implementation environment. For example:
- Browser implementations can't set headers, so use the WebSocket protocol
- If your library doesn't support protocol modification, use the query parameter
Handle your API key securely! Be especially careful with logging, which can accidentally expose your key.
Examples
- node sdk
- Node.js
- go sdk
Simplified example of usage with eyeson-node.
import Eyeson from 'eyeson-node';
const eyeson = new Eyeson({ apiKey: '< api-key >' }); // configure to use your api key
const meeting = await eyeson.join(username);
const connection = eyeson.observer.connect(meeting.roomId);
connection.on('disconnected', reason => {
console.log('Channel closed', reason);
});
connection.on('event', event => {
if (event.type === 'room_update') {
console.log(event.content);
}
else if (event.type === 'chat') {
console.log(event.content);
}
else if (event.type === 'participant_update') {
console.log(event.participant);
}
// and many more
});
The observer is already integrated in the Node.js library.
import WebSocket from 'ws';
import { createCable } from '@anycable/core';
let cable = null;
const connect = (room_id) => {
const url = `https://api.eyeson.team/rt?room_id=${room_id}`;
cable = createCable(url, {
websocketImplementation: WebSocket,
websocketOptions: {
headers: {
'Authorization': process.env.API_KEY,
},
},
});
const channel = cable.subscribeTo('RoomChannel');
channel.on('message', onMessage);
channel.on('connect', onConnected);
channel.on('disconnect', onDisconnected);
};
const disconnect = () => {
if (cable) {
cable.disconnect();
cable = null;
}
};
const onMessage = message => {
if (message.type === 'room_update') {
if (message.content.ready === true) {
console.log('Meeting ready');
}
if (message.content.shutdown === true) {
console.log('Meeting shutdown - disconnect');
disconnect();
}
}
};
const onConnected = () => {
console.log('Connected');
};
const onDisconnected = ({ name, message, reason }) => {
console.log('Disconnected', name, message, reason);
if (reason === 'unauthorized') {
disconnect();
}
};
The observer is already integrated in the Go library. Simplified example of usage with eyeson-go.
client, _ := eyeson.NewClient(eyesonApiKey)
room, _ := client.Rooms.Join("standup meeting", "mike")
msgCh, _ := client.Observer.Connect(context.Background(), room.Data.Room.ID)
for {
select {
case msg, ok := <-msgCh:
if !ok {
fmt.Println("Channel closed. Probably disconnected")
return
}
fmt.Println("Received event type: ", msg.GetType())
switch m := msg.(type) {
case *eyeson.Chat:
fmt.Printf("Chat: %s - %s\n", m.ClientID, m.Content)
}
}
}
Events
This is a list with examples of all events that can be observed during a meeting.
room_update
Received after connection is established, when the room is ready, or room shutdown changes to true.
Also see: Meeting Room Endpoint
{
"type": "room_update",
"content": {
"id": "6576daef1f138900153d0762",
"name": "Observer demo",
"ready": true,
"started_at": "2023-12-11T09:48:32.031Z",
"shutdown": false,
"guest_token": "jCWzhzCWONkbIubUYF7PD3hP",
"options": {
"show_names": true,
"show_label": true,
"exit_url": null,
"recording_available": true,
"broadcast_available": true,
"layout_available": true,
"layout": "auto",
"reaction_available": true,
"suggest_guest_names": true,
"lock_available": true,
"kick_available": true,
"sfu_mode": "ptp",
"layout_users": null,
"layout_name": null,
"layout_map": null,
"voice_activation": false,
"custom_fields": {},
"widescreen": true,
"background_color": "#121212"
},
"participants": [],
"playbacks": [],
"presentation": null,
"broadcasts": [],
"recording": null
}
}
You can already see all current participants, playbacks, broadcasts, and the recording's active state.
When the meeting shuts down, the connection is automatically closed.
participant_update
As soon as a participant joins or leaves the meeting, this event is triggered and you can determine join or leave by the online
parameter.
Also see: User Endpoint
{
"type": "participant_update",
"participant": {
"id": "test@observer.com",
"room_id": "6576daef1f138900153d0762",
"name": "Observer",
"avatar": null,
"guest": false,
"online": true
}
}
recording_update
Each recording has 3 states. Start, stop, and finish. So you will receive 3 events and you can distinguish them by the duration
and links.download
fields.
- At start, both are
null
- At stop, duration is set, but download is
null
- At finish, both are set
Also see: Recording Endpoint
{
"type": "recording_update",
"recording": {
"id": "6576db593df56e00150ae3ce",
"created_at": 1702288218,
"duration": 5,
"links": {
"self": "https://api.eyeson.team/recordings/6576db593df56e00150ae3ce",
"download": "https://fs.eyeson.com/meetings/6576daf01f138900153d0763/6576db593df56e00150ae3ce.webm?X-Amz-Algorithm=..."
},
"user": {
"id": "test@observer.com",
"name": "Observer",
"avatar": null,
"guest": false,
"joined_at": "2023-12-11T09:48:34.433Z"
},
"room": {
"id": "6576daef1f138900153d0762",
"name": "Observer demo",
"ready": true,
"started_at": "2023-12-11T09:48:32.031Z",
"shutdown": false,
"guest_token": "jCWzhzCWONkbIubUYF7PD3hP"
}
}
}
broadcasts_update
When a live stream starts, the broadcasts array will be filled. When it ends, the broadcasts array is empty.
Also see: Broadcast Endpoint
{
"type": "broadcasts_update",
"broadcasts": [
{
"id": "generic",
"platform": "generic",
"player_url": "",
"user": {
"id": "test@observer.com",
"name": "Observer",
"avatar": null,
"guest": false,
"joined_at": "2023-12-11T09:48:34.433Z"
},
"room": {
"id": "6576daef1f138900153d0762",
"name": "Observer demo",
"ready": true,
"started_at": "2023-12-11T09:48:32.031Z",
"shutdown": false,
"guest_token": "jCWzhzCWONkbIubUYF7PD3hP"
}
}
]
}
options_update
This is for layout changes and its related fields only.
show_names
, layout
, layout_users
, layout_name
, layout_map
, and voice_activation
.
Also see: Layout Endpoint
{
"type": "options_update",
"options": {
"show_names": true,
"show_label": true,
"exit_url": null,
"recording_available": true,
"broadcast_available": true,
"layout_available": true,
"layout": "auto",
"reaction_available": true,
"suggest_guest_names": true,
"lock_available": true,
"kick_available": true,
"sfu_mode": "ptp",
"layout_users": [
"",
"",
"",
"",
"",
"",
"",
"",
""
],
"layout_name": "nine",
"layout_map": null,
"voice_activation": false,
"custom_fields": {},
"widescreen": true,
"background_color": "#121212"
}
}
snapshot_update
When a snapshot is created during a meeting, this event provides complete details about it, including download links, creator information, and timestamp data.
Also see: Snapshot Endpoint
{
"type": "snapshot_update",
"snapshots": [
{
"id": "6576dd5ee71541001518fc11",
"name": "1702288734",
"links": {
"download": "https://fs.eyeson.com/meetings/6576daf01f138900153d0763/snapshots/1702288734.jpg?X-Amz-Algorithm=..."
},
"creator": {
"id": "test@observer.com",
"name": "Observer",
"avatar": null,
"guest": false,
"joined_at": "2023-12-11T09:48:34.433Z"
},
"created_at": "2023-12-11T09:58:54.498Z",
"room": {
"id": "6576daef1f138900153d0762",
"name": "Observer demo",
"ready": true,
"started_at": "2023-12-11T09:48:32.031Z",
"shutdown": false,
"guest_token": "jCWzhzCWONkbIubUYF7PD3hP"
}
}
]
}
chat
Chat messages are messages with type chat
sent over the API messages endpoint.
Also see: Messages Endpoint
{
"type": "chat",
"content": "Hello world!",
"cid": "6576daf01f138900153d0764",
"user_id": "test@observer.com",
"created_at": "2023-12-11T09:59:33.892Z"
}
custom
Custom messages are messages with type custom
sent over the API messages endpoint, which do not show up in the prebuilt UI's chat sidebar.
Also see: Messages Endpoint
{
"type": "custom",
"content": "Your custom message",
"cid": "6576daf01f138900153d0764",
"user_id": "test@observer.com",
"created_at": "2023-12-11T10:01:49.353Z"
}
playback_update
The playing
parameter is a list of all currently active playbacks. If one playback ends, a playback_update
event is received where the playing list does not contain the ended playback anymore. When the list is empty, all playbacks have ended.
Also see: Playback Endpoint
{
"type": "playback_update",
"playing": [
{
"play_id": "demo-video",
"url": "https://myawesomeapp.com/videos/demo-video.webm",
"name": null,
"audio": true,
"loop_count": 0,
"replacement_id": null
}
]
}
podium_update
This event provides information about the current state of Eyeson One View's display configuration. It details how the view is segmented and which content appears in each segment, identified either by a participant's user_id
or a playback's play_id
. This data enables you to track the precise arrangement of participants and media in the meeting's visual layout.
Also see: Layers Endpoint, Layout Endpoint
This event includes layers. The layers
list is empty if no layers are set.
{
"type": "podium_update",
"podium": [
{
"user_id": "test@observer.com",
"play_id": null,
"width": 427,
"height": 240,
"left": 0,
"top": 0,
"z-index": 0
},
{
"user_id": null,
"play_id": null,
"width": 427,
"height": 240,
"left": 427,
"top": 0,
"z-index": 1
},
{
"user_id": null,
"play_id": null,
"width": 426,
"height": 240,
"left": 854,
"top": 0,
"z-index": 2
},
{
"user_id": null,
"play_id": null,
"width": 427,
"height": 240,
"left": 0,
"top": 240,
"z-index": 3
},
{
"user_id": null,
"play_id": null,
"width": 427,
"height": 240,
"left": 427,
"top": 240,
"z-index": 4
},
{
"user_id": null,
"play_id": null,
"width": 426,
"height": 240,
"left": 854,
"top": 240,
"z-index": 5
},
{
"user_id": null,
"play_id": null,
"width": 427,
"height": 240,
"left": 0,
"top": 480,
"z-index": 6
},
{
"user_id": null,
"play_id": null,
"width": 427,
"height": 240,
"left": 427,
"top": 480,
"z-index": 7
},
{
"user_id": null,
"play_id": null,
"width": 426,
"height": 240,
"left": 854,
"top": 480,
"z-index": 8
}
],
"layers": [
{
"z-index": 1,
"id": "da9c96e70034e45d1ba2b80a304c0808"
},
{
"z-index": -1,
"id": "fc26523a13be45fcf1728a5f7360e611"
}
]
}
lock
When the meeting room gets locked, you will receive this information.
Also see: Meeting Room Endpoint
{
"type": "lock",
"locked": true
}
presentation_update
A presentation is indicated by the presentation
parameter. The user
is the one who started the presentation. presentation
is set to null
if the presentation has stopped.
Presentation updates are triggered when a user starts a screenshare or shares a file in the prebuilt UI.
{
"type": "presentation_update",
"presentation": {
"room": {
"id": "6576daef1f138900153d0762",
"name": "Observer demo",
"ready": true,
"started_at": "2023-12-11T09:48:32.031Z",
"shutdown": false,
"guest_token": "jCWzhzCWONkbIubUYF7PD3hP"
},
"user": {
"id": "test@observer.com",
"name": "Observer",
"avatar": null,
"guest": false,
"joined_at": "2023-12-11T09:48:34.433Z"
}
}
}
Errors
In the following cases, the websocket connection can't be established.
Invalid or missing API key
The WebSocket will close the connection with the following message:
{ "type": "disconnect", "reason": "unauthorized", "reconnect": false }
Invalid or missing ROOM_ID
The WebSocket will close the connection with the following message:
{ "type": "disconnect", "reason": "unauthorized", "reconnect": false }