Skip to main content
The Recall AI SDK provides a powerful Bot class for creating and managing bots that can join video meetings, record content, and extract data.

Initializing the SDK

First, initialize the Recall SDK with your API key and region:
import { Recall } from '@recall-ai/sdk';

const recall = new Recall({
  apiKey: 'your-api-key',
  region: 'us-west-2'
});

Creating a bot

1

Create a bot with a meeting URL

Use the create method to send a bot to a meeting:
const bot = await recall.bot.create({
  meeting_url: 'https://zoom.us/j/123456789',
  bot_name: 'My Recording Bot'
});

console.log(bot.id); // Bot ID for future reference
2

Configure bot settings

Customize the bot’s behavior with additional configuration:
const bot = await recall.bot.create({
  meeting_url: 'https://meet.google.com/abc-defg-hij',
  bot_name: 'Sales Call Recorder',
  recording_mode: 'speaker_view',
  recording_mode_options: {
    participant_video_when_screenshare: 'hide',
    start_recording_on: 'bot_join'
  },
  transcription_options: {
    provider: 'assembly_ai'
  }
});
3

Schedule a bot for later

Schedule a bot to join at a specific time:
const scheduledBot = await recall.bot.create({
  meeting_url: 'https://teams.microsoft.com/l/meetup-join/...',
  bot_name: 'Future Meeting Bot',
  join_at: new Date('2024-12-25T10:00:00Z')
});

Bot configuration parameters

Basic parameters

meeting_url
string
required
The URL of the meeting for the bot to join. Supports Zoom, Google Meet, Microsoft Teams, and other platforms.
bot_name
string
The display name for the bot in the meeting. Defaults to “Meeting Bot”.
join_at
Date
Schedule the bot to join at a specific time. If not provided, the bot joins immediately.

Recording configuration

recording_mode
string
The recording layout mode:
  • speaker_view - Focus on the active speaker
  • gallery_view - Show all participants
  • audio_only - Record only audio
recording_mode_options
RecordingModeOptions
Additional recording options:
{
  participant_video_when_screenshare?: string; // 'hide' or 'show'
  start_recording_on?: string; // 'bot_join' or 'manual'
}

Transcription settings

transcription_options
TranscriptionOptions
Configure transcription provider:
{
  provider: string; // 'assembly_ai', 'deepgram', etc.
}

Real-time features

real_time_transcription
RealTimeTranscription
Enable real-time transcription streaming:
{
  destination_url?: string;
  partial_results?: boolean;
  enhanced_diarization?: boolean;
}
real_time_media
RealTimeMedia
Configure real-time media streaming:
{
  rtmp_destination_url?: string;
  websocket_video_destination_url?: string;
  websocket_audio_destination_url?: string;
  websocket_speaker_timeline_destionation_url?: string;
  websocket_speaker_timeline_exclude_null_speaker?: boolean;
  webhook_call_events_destination_url?: string;
  webhook_chat_messages_destination_url?: string;
}

Visual customization

automatic_video_output
AutomaticVideoOutput
Customize the bot’s video appearance:
{
  in_call_recording?: {
    kind: string;
    b64_data: string; // Base64 encoded image
  };
  in_call_not_recording?: {
    kind: string;
    b64_data: string;
  };
}

Retrieving bot information

Get detailed information about a specific bot:
const botInfo = await recall.bot.retrieve({ id: 'bot-id' });

console.log(botInfo.status); // Current bot status
console.log(botInfo.meeting_url); // Meeting details

Listing bots

Query and filter your bots:
const bots = await recall.bot.list({});

bots.forEach(bot => {
  console.log(`${bot.id}: ${bot.status}`);
});

Bot status values

Bots progress through various states during their lifecycle:
StatusDescription
readyBot is created and ready to join
joining_callBot is attempting to join the meeting
in_waiting_roomBot is waiting to be admitted
in_call_not_recordingBot has joined but not yet recording
recording_permission_allowedRecording permission granted
recording_permission_deniedRecording permission denied
in_call_recordingBot is actively recording
recording_doneRecording has finished
call_endedMeeting has ended
doneAll processing complete
fatalBot encountered an error
media_expiredRecording media has expired
analysis_donePost-recording analysis complete
analysis_failedAnalysis failed

Managing scheduled bots

Update a scheduled bot

Modify a bot’s configuration before it joins:
const updated = await recall.bot.updateScheduledBot({
  id: 'bot-id',
  bot_name: 'Updated Bot Name',
  join_at: new Date('2024-12-25T15:00:00Z'),
  recording_mode: 'gallery_view'
});
You can only update scheduled bots that haven’t joined the meeting yet. Bots with status ready or joining_call can be updated.

Delete a scheduled bot

Cancel a scheduled bot before it joins:
await recall.bot.deleteScheduledBot({ id: 'bot-id' });

Bot intelligence

Retrieve AI-generated insights from the bot’s recording:
const intelligence = await recall.bot.getBotIntellienge({ id: 'bot-id' });

console.log(intelligence.summary);
console.log(intelligence.action_items);
console.log(intelligence.key_points);
Intelligence is available once the bot status reaches analysis_done.

Bot logs

Debug bot behavior by retrieving detailed logs:
const logs = await recall.bot.getBotLogs({ id: 'bot-id' });

logs.forEach(log => {
  console.log(`[${log.timestamp}] ${log.level}: ${log.message}`);
});

Chat messages

Retrieve chat messages from the meeting:
const messages = await recall.bot.listChatMessages({
  id: 'bot-id',
  ordering: '-created_at'
});

messages.forEach(msg => {
  console.log(`${msg.sender}: ${msg.message}`);
});

Pagination with chat messages

let cursor = null;
let allMessages = [];

do {
  const response = await recall.bot.listChatMessages({
    id: 'bot-id',
    cursor: cursor
  });
  
  allMessages = allMessages.concat(response.results);
  cursor = response.next_cursor;
} while (cursor);

Output audio during call

Make the bot play audio during an active call:
// Convert audio file to base64
const audioBase64 = fs.readFileSync('audio.mp3').toString('base64');

await recall.bot.outputAudio({
  id: 'bot-id',
  kind: 'audio/mp3',
  b64_data: audioBase64
});
The bot must be in an active call (in_call_recording or in_call_not_recording status) to output audio.

Best practices

Monitor bot status

Regularly check the bot status to handle any issues promptly, especially recording_permission_denied and fatal states.

Handle waiting rooms

Be prepared to admit bots from waiting rooms, either manually or through automated workflows.

Use meaningful names

Give bots clear, descriptive names so meeting participants understand their purpose.

Clean up media

Delete bot media when no longer needed to manage storage costs (see the managing recordings guide).

Complete example

Here’s a complete workflow for creating and monitoring a bot:
import { Recall } from '@recall-ai/sdk';

const recall = new Recall({
  apiKey: process.env.RECALL_API_KEY,
  region: 'us-west-2'
});

async function recordMeeting(meetingUrl) {
  try {
    // Create bot
    const bot = await recall.bot.create({
      meeting_url: meetingUrl,
      bot_name: 'Sales Meeting Recorder',
      recording_mode: 'speaker_view',
      transcription_options: {
        provider: 'assembly_ai'
      },
      real_time_transcription: {
        destination_url: 'https://yourapp.com/webhooks/transcript',
        enhanced_diarization: true
      }
    });

    console.log(`Bot created: ${bot.id}`);

    // Monitor bot status
    let status = 'ready';
    while (!['done', 'fatal', 'call_ended'].includes(status)) {
      await new Promise(resolve => setTimeout(resolve, 5000));
      
      const botInfo = await recall.bot.retrieve({ id: bot.id });
      status = botInfo.status;
      
      console.log(`Bot status: ${status}`);
      
      if (status === 'recording_permission_denied') {
        console.error('Recording permission denied!');
        break;
      }
    }

    // Get final data
    if (status === 'done') {
      const transcript = await recall.bot.getTranscript({ 
        id: bot.id,
        enhanced_diarization: true 
      });
      
      const intelligence = await recall.bot.getBotIntellienge({ id: bot.id });
      
      return { transcript, intelligence };
    }
  } catch (error) {
    console.error('Error recording meeting:', error);
    throw error;
  }
}

// Usage
recordMeeting('https://zoom.us/j/123456789')
  .then(data => console.log('Recording complete:', data))
  .catch(err => console.error('Recording failed:', err));

Build docs developers (and LLMs) love