Skip to main content

Quick Start Guide

This guide walks you through creating a basic video conference using lib-jitsi-meet. You’ll learn the essential steps: initialization, creating local tracks, connecting to a server, and joining a conference.

Prerequisites

  • lib-jitsi-meet installed (Installation Guide)
  • A Jitsi Meet deployment or JaaS (Jitsi as a Service) account
  • Modern browser with WebRTC support

Basic Conference Flow

The typical flow for creating a conference:
1

Initialize JitsiMeetJS

Call init() before using any other library functions:
import JitsiMeetJS from 'lib-jitsi-meet';

// Initialize with options
JitsiMeetJS.init({
  enableAnalyticsLogging: false,
  disableAudioLevels: false,
  disableThirdPartyRequests: false,
});
Available initialization options (from JitsiMeetJS.ts:89-106):
interface IJitsiMeetJSOptions {
  analytics?: {
    rtcstatsLogFlushSizeBytes?: number;
    rtcstatsStoreLogs?: boolean;
  };
  audioLevelsInterval?: number;
  desktopSharingSources?: Array<'screen' | 'window'>;
  disableAudioLevels?: boolean;
  disableThirdPartyRequests?: boolean;
  enableAnalyticsLogging?: boolean;
  enableWindowOnErrorHandler?: boolean;
  externalStorage?: Storage;
  flags?: {
    runInLiteMode?: boolean;
    ssrcRewritingEnabled?: boolean;
  };
  pcStatsInterval?: number;
}
2

Create Local Tracks

Request access to camera and microphone:
// Create audio and video tracks
const tracks = await JitsiMeetJS.createLocalTracks({
  devices: ['audio', 'video'],
  resolution: '720',
  constraints: {
    video: {
      height: { ideal: 720, max: 720, min: 180 },
      width: { ideal: 1280, max: 1280, min: 320 }
    }
  }
});

// Attach tracks to DOM elements
tracks.forEach(track => {
  if (track.getType() === 'video') {
    const videoElement = document.getElementById('localVideo');
    track.attach(videoElement);
  } else {
    const audioElement = document.getElementById('localAudio');
    track.attach(audioElement);
  }
});
Options for createLocalTracks() (from JitsiMeetJS.ts:79-85):
interface ICreateLocalTrackOptions {
  cameraDeviceId?: string;      // Specific camera device ID
  devices?: any[];              // Array of 'audio', 'video', 'desktop'
  fireSlowPromiseEvent?: boolean;
  micDeviceId?: string;         // Specific microphone device ID
  resolution?: string;          // '720', '1080', etc.
}
3

Create JitsiConnection

Establish a connection to the Jitsi Meet server:
import { JitsiConnectionEvents } from 'lib-jitsi-meet/JitsiConnectionEvents';

const connection = new JitsiMeetJS.JitsiConnection(
  null,  // appId (optional for self-hosted)
  null,  // token (JWT for authentication)
  {
    hosts: {
      domain: 'meet.jit.si',
      muc: 'conference.meet.jit.si'
    },
    serviceUrl: 'wss://meet.jit.si/xmpp-websocket',
    enableWebsocketResume: true
  }
);

// Handle connection events
connection.addEventListener(
  JitsiConnectionEvents.CONNECTION_ESTABLISHED,
  onConnectionSuccess
);

connection.addEventListener(
  JitsiConnectionEvents.CONNECTION_FAILED,
  onConnectionFailed
);

connection.addEventListener(
  JitsiConnectionEvents.CONNECTION_DISCONNECTED,
  onDisconnected
);

// Connect
connection.connect();
Connection options (from JitsiConnection.ts:16-34):
interface IConnectionOptions {
  hosts: {
    domain: string;           // XMPP domain
    muc?: string;            // Multi-user chat domain
  };
  serviceUrl: string;         // WebSocket URL
  enableWebsocketResume: boolean;
  websocketKeepAlive?: number;
  websocketKeepAliveUrl?: string;
  p2pStunServers?: any[];
}
4

Initialize and Join Conference

Once connected, create and join a conference:
import { JitsiConferenceEvents } from 'lib-jitsi-meet/JitsiConferenceEvents';

function onConnectionSuccess() {
  // Create conference
  const conference = connection.initJitsiConference('my-room-name', {
    openBridgeChannel: true,
    p2p: {
      enabled: true,
      preferredCodec: 'VP9'
    }
  });
  
  // Add local tracks
  tracks.forEach(track => conference.addTrack(track));
  
  // Handle conference events
  conference.on(JitsiConferenceEvents.TRACK_ADDED, onRemoteTrack);
  conference.on(JitsiConferenceEvents.TRACK_REMOVED, onTrackRemoved);
  conference.on(JitsiConferenceEvents.USER_JOINED, onUserJoined);
  conference.on(JitsiConferenceEvents.USER_LEFT, onUserLeft);
  conference.on(JitsiConferenceEvents.CONFERENCE_JOINED, onConferenceJoined);
  
  // Join the conference
  conference.join();
}

function onConferenceJoined() {
  console.log('Successfully joined conference!');
}
5

Handle Remote Tracks

Display remote participant media:
import { JitsiTrackEvents } from 'lib-jitsi-meet/JitsiTrackEvents';

function onRemoteTrack(track) {
  if (track.isLocal()) return;
  
  const participantId = track.getParticipantId();
  
  // Create container for remote participant
  if (!document.getElementById(participantId)) {
    const container = document.createElement('div');
    container.id = participantId;
    document.getElementById('remoteVideos').appendChild(container);
  }
  
  // Attach the track
  if (track.getType() === 'video') {
    const video = document.createElement('video');
    video.autoplay = true;
    video.id = `${participantId}-video`;
    document.getElementById(participantId).appendChild(video);
    track.attach(video);
  } else {
    const audio = document.createElement('audio');
    audio.autoplay = true;
    audio.id = `${participantId}-audio`;
    document.getElementById(participantId).appendChild(audio);
    track.attach(audio);
  }
}

function onTrackRemoved(track) {
  if (track.isLocal()) return;
  
  const id = track.getType() === 'video' 
    ? `${track.getParticipantId()}-video`
    : `${track.getParticipantId()}-audio`;
  
  const element = document.getElementById(id);
  if (element) {
    element.remove();
  }
}

Complete Example

Here’s a complete working example:
import JitsiMeetJS from 'lib-jitsi-meet';
import { JitsiConnectionEvents } from 'lib-jitsi-meet/JitsiConnectionEvents';
import { JitsiConferenceEvents } from 'lib-jitsi-meet/JitsiConferenceEvents';

let connection = null;
let conference = null;
let localTracks = [];

// Initialize
JitsiMeetJS.init();

// Set log level (optional)
JitsiMeetJS.setLogLevel(JitsiMeetJS.logLevels.ERROR);

async function joinConference(roomName) {
  try {
    // Create local tracks
    localTracks = await JitsiMeetJS.createLocalTracks({
      devices: ['audio', 'video']
    });
    
    // Attach local tracks to DOM
    localTracks.forEach(track => {
      if (track.getType() === 'video') {
        track.attach(document.getElementById('localVideo'));
      }
    });
    
    // Create connection
    connection = new JitsiMeetJS.JitsiConnection(null, null, {
      hosts: {
        domain: 'meet.jit.si',
        muc: 'conference.meet.jit.si'
      },
      serviceUrl: 'wss://meet.jit.si/xmpp-websocket',
      enableWebsocketResume: true
    });
    
    // Connection event handlers
    connection.addEventListener(
      JitsiConnectionEvents.CONNECTION_ESTABLISHED,
      () => onConnectionEstablished(roomName)
    );
    
    connection.addEventListener(
      JitsiConnectionEvents.CONNECTION_FAILED,
      (error) => console.error('Connection failed:', error)
    );
    
    // Connect
    connection.connect();
    
  } catch (error) {
    console.error('Error joining conference:', error);
  }
}

function onConnectionEstablished(roomName) {
  // Initialize conference
  conference = connection.initJitsiConference(roomName, {
    openBridgeChannel: true
  });
  
  // Conference event handlers
  conference.on(JitsiConferenceEvents.CONFERENCE_JOINED, () => {
    console.log('Conference joined!');
  });
  
  conference.on(JitsiConferenceEvents.TRACK_ADDED, (track) => {
    if (!track.isLocal()) {
      const participantId = track.getParticipantId();
      const element = track.getType() === 'video' 
        ? document.getElementById(`remote-video-${participantId}`)
        : document.getElementById(`remote-audio-${participantId}`);
      
      if (element) {
        track.attach(element);
      }
    }
  });
  
  conference.on(JitsiConferenceEvents.USER_JOINED, (id, user) => {
    console.log('User joined:', id);
  });
  
  conference.on(JitsiConferenceEvents.USER_LEFT, (id) => {
    console.log('User left:', id);
  });
  
  // Add local tracks
  localTracks.forEach(track => conference.addTrack(track));
  
  // Join conference
  conference.join();
}

// Usage
joinConference('my-test-room');

Simplified API with joinConference()

For JaaS users, lib-jitsi-meet provides a simplified joinConference() method that handles everything automatically (from JitsiMeetJS.ts:448-526):
// Simple JaaS conference join
const conference = await JitsiMeetJS.joinConference(
  'my-room-name',
  'vpaas-magic-cookie-1234567890abcdef',  // JaaS app ID
  'your-jwt-token',
  {
    tracks: localTracks,  // Optional: pre-created tracks
    conferenceOptions: {
      openBridgeChannel: true
    }
  }
);

// Conference is ready to use
conference.on(JitsiConferenceEvents.USER_JOINED, (id) => {
  console.log('User joined:', id);
});
This method automatically:
  • Configures JaaS endpoints and domains
  • Creates the connection
  • Initializes the conference
  • Adds tracks and joins
  • Sets up receiver constraints

Event Handling Reference

Key events you’ll commonly handle: Connection Events (from JitsiConnectionEvents)
  • CONNECTION_ESTABLISHED - Connected to server
  • CONNECTION_FAILED - Connection failed
  • CONNECTION_DISCONNECTED - Disconnected from server
Conference Events (from JitsiConferenceEvents)
  • CONFERENCE_JOINED - Successfully joined conference
  • CONFERENCE_LEFT - Left the conference
  • USER_JOINED - Remote participant joined
  • USER_LEFT - Remote participant left
  • TRACK_ADDED - Media track added (local or remote)
  • TRACK_REMOVED - Media track removed
  • TRACK_MUTE_CHANGED - Track mute status changed
  • DISPLAY_NAME_CHANGED - Participant display name changed
  • DOMINANT_SPEAKER_CHANGED - Active speaker changed
Track Events (from JitsiTrackEvents)
  • TRACK_AUDIO_LEVEL_CHANGED - Audio level changed
  • TRACK_MUTE_CHANGED - Mute status changed
  • LOCAL_TRACK_STOPPED - Local track stopped
  • NO_DATA_FROM_SOURCE - No data from media source

Next Steps

API Reference

Explore the complete API documentation

Advanced Features

Learn about E2EE, screen sharing, and quality control

Build docs developers (and LLMs) love