How to get Separate Videos per Participant (Realtime)

Receive video data for each participant in realtime over websocket

📘

Video data streaming is currently supported in PNG and H264 formats

📘

H264 video per participant is currently only available on bots with the web4core variant

Receive separate live videos of each participant in PNG or H264 Formats over websocket in realtime

Platforms Support

SupportedPlatform
Zoom
Microsoft Teams
Google Meet
Webex
Slack Huddles (Beta)
Go-To Meeting (Beta)

PNG Recording Specifications

PNG ResolutionResolutionFrame Rate
Screen Share360p2 frames per second
Participant360p2 frames per second

H264 Recording Specifications

H264 buffers retrieved are at the resolution that we receive from the meeting platform, which can change during the meeting based on the number of participants and the connection quality of each participant's connection.

H264 ResolutionResolutionFrame Rate
Screen Share240px-1280px typical10-30 frames per second typical
Participant200px-1000px typical10-30 frames per second typical

Implementation

Step 1: Create a bot

To get separate video per participant, you must set recording_config.video_mixed_layout = "gallery_view_v2". Below is an example of what it would look like in your request

PNG Format

curl --request POST \
     --url https://us-east-1.recall.ai/api/v1/bot \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'authorization: YOUR_RECALL_API_KEY' \
     --data '
{
  "meeting_url": "YOUR_MEETING_URL",
  "recording_config": {
    "video_mixed_layout": "gallery_view_v2",
    "video_separate_png": {},
    "realtime_endpoints": [
      {
      	type: "websocket",
        url: YOUR_WEBSOCKET_RECEIVER_URL,
        events: ["video_separate_png.data"]
      }
    ]
  }
}
'
const response = await fetch("https://us-east-1.recall.ai/api/v1/bot", {
  method: "POST",
  headers: {
    "accept": "application/json",
    "content-type": "application/json"
    "authorization": YOUR_RECALL_API_KEY
  },
  body: JSON.stringify({
    meeting_url: YOUR_MEETING_URL,
    recording_config: {
      video_mixed_layout: "gallery_view_v2",
      video_separate_png: {},
      realtime_endpoints: [
        {
          type: "websocket",
          url: YOUR_WEBSOCKET_RECEIVER_URL,
          events: ["video_separate_png.data"]
        }
      ]	
    }
  })
});

if (!response.ok) {
  throw new Error(`Error: ${response.status} ${response.statusText}`);
}
const data = await response.json();
import requests

response = requests.post(
    "https://us-east-1.recall.ai/api/v1/bot",
    json={
      "meeting_url": "YOUR_MEETING_URL",
      "recording_config": {
	      "video_mixed_layout": "gallery_view_v2"
        "video_separate_png": {},
  			"realtime_endpoints": [
        	{
            type: "websocket",
            url: YOUR_WEBSOCKET_RECEIVER_URL,
            events: ["video_separate_png.data"]
          }
      	]
      }
    },
    headers={
      "accept": "application/json",
      "content-type": "application/json",
    	"authorization": YOUR_RECALL_API_KEY
    }
)

if not response.ok:
 	errorMessage = f"Error: {response.status_code} - {response.text}"
  raise requests.RequestException(errorMessage)
result = response.json()

H264 Format

curl --request POST \
     --url https://us-east-1.recall.ai/api/v1/bot \
     --header 'accept: application/json' \
     --header 'content-type: application/json' \
     --header 'authorization: YOUR_RECALL_API_KEY' \
     --data '
{
  "meeting_url": "YOUR_MEETING_URL",
  "variant": {
    "zoom": "web_4_core",
    "google_meet": "web_4_core",
    "microsoft_teams": "web_4_core"
    },
  "recording_config": {
    "video_mixed_layout": "gallery_view_v2",
    "video_separate_h264": {},
    "realtime_endpoints": [
      {
      	type: "websocket",
        url: "YOUR_WEBSOCKET_RECEIVER_URL",
        events: ["video_separate_h264.data"]
      }
    ]
  }
}
'
const response = await fetch("https://us-east-1.recall.ai/api/v1/bot", {
  method: "POST",
  headers: {
    "accept": "application/json",
    "content-type": "application/json"
    "authorization": YOUR_RECALL_API_KEY
  },
  body: JSON.stringify({
    meeting_url: YOUR_MEETING_URL,
    variant: {
      zoom: "web_4_core",
      google_meet: "web_4_core",
      microsoft_teams: "web_4_core"
    },
    recording_config: {
      video_mixed_layout: "gallery_view_v2",
      video_separate_h264: {},
      realtime_endpoints: [
        {
          type: "websocket",
          url: YOUR_WEBSOCKET_RECEIVER_URL,
          events: ["video_separate_h264.data"]
        }
      ]	
    }
  })
});

if (!response.ok) {
  throw new Error(`Error: ${response.status} ${response.statusText}`);
}

const data = await response.json();
import requests

response = requests.post(
    "https://us-east-1.recall.ai/api/v1/bot",
    json={
      "meeting_url": YOUR_MEETING_URL,
      "variant": {
        "zoom": "web_4_core",
        "google_meet": "web_4_core",
        "microsoft_teams": "web_4_core"
      },
      "recording_config": {
        "video_mixed_layout": "gallery_view_v2"
        "video_separate_h264": {},
        "realtime_endpoints": [
          {
            "type": "websocket",
            "url": YOUR_WEBSOCKET_RECEIVER_URL,
            "events": ["video_separate_h264.data"]
          }
        ]
      }
    },
    headers={
      "accept": "application/json",
      "content-type": "application/json",
    	"authorization": YOUR_RECALL_API_KEY
    }
)

if not response.ok:
 	errorMessage = f"Error: {response.status_code} - {response.text}"
  raise requests.RequestException(errorMessage)
  
result = response.json()

Step 2: Receive websocket messages with video data

Setup a websocket server and ensure it is publicly accessible. You will receive messages in the following payload format:

PNG Format

{
  "event": "video_separate_png.data", 
  "data": {
    "data": {
      "buffer": string, // base64 encoded png at 2fps with resolution 360x640
      "timestamp": {
      	"relative": float,
        "absolute": string
    	},
      "type": "webcam" | "screenshare",
      "participant": {
      	"id": number,
      	"name": string | null,
        "is_host": boolean,
        "platform": string | null,
        "extra_data": object
      }
    },
    "realtime_endpoint": {
      "id": string,
      "metadata": object,
    },
    "video_separate": {
      "id": string,
      "metadata": object
    },
    "recording": {
      "id": string,
      "metadata": object
    },
    "bot": {
      "id": string,
      "metadata": object
    },
  }
}

H264 Format

{
  "event": "video_separate_h264.data", 
  "data": {
    "data": {
      "buffer": string, // base64 h264 at a resolution and framerate set by the platform
      "timestamp": {
      	"relative": float,
        "absolute": string
    	},
      "type": "webcam" | "screenshare",
      "participant": {
      	"id": number,
      	"name": string | null,
        "is_host": boolean,
        "platform": string | null,
        "extra_data": object
      }
    },
    "realtime_endpoint": {
      "id": string,
      "metadata": object,
    },
    "video_separate": {
      "id": string,
      "metadata": object
    },
    "recording": {
      "id": string,
      "metadata": object
    },
    "bot": {
      "id": string,
      "metadata": object
    },
  }
}

Step 3 Decode Video

For H264 live video, checkout our Browser Sample and our Python Sample