Skip to main content
You need a Daily account and a room URL to complete this guide. Create a free account at daily.co and create a room from the dashboard to get a URL in the format https://your-domain.daily.co/room-name.

Choose your integration mode

daily-js supports two integration modes. Pick the one that fits your use case:
  • Iframe mode — Daily renders a full-featured call UI (participant tiles, controls, chat) inside an <iframe>. Minimal code required.
  • Call object mode — Daily handles media with no built-in UI. You build the interface entirely yourself.
1

Install the package

Add @daily-co/daily-js to your project:
npm install @daily-co/daily-js
2

Create a call frame

Import DailyIframe and call createFrame(). This creates an <iframe> element and appends it to document.body by default.
import Daily from '@daily-co/daily-js';

const callFrame = Daily.createFrame();
To mount the iframe inside a specific container instead of document.body, pass the element as the first argument:
const container = document.getElementById('call-container');
const callFrame = Daily.createFrame(container);
You can also pass style options:
const callFrame = Daily.createFrame({
  iframeStyle: {
    position: 'fixed',
    width: '100%',
    height: '100%',
    top: 0,
    left: 0,
    border: 0,
  },
});
3

Join a room

Call join() with your room URL. This returns a promise that resolves once you have entered the meeting.
await callFrame.join({ url: 'https://your-domain.daily.co/room-name' });
4

Listen for events

Subscribe to call events using .on(). The joined-meeting event fires once you are connected and includes the current participants.
callFrame
  .on('joined-meeting', (event) => {
    console.log('Joined!', event.participants);
  })
  .on('participant-joined', (event) => {
    console.log('Participant joined:', event.participant.user_name);
  })
  .on('participant-left', (event) => {
    console.log('Participant left:', event.participant.user_name);
  })
  .on('error', (event) => {
    console.error('Call error:', event.errorMsg);
  });
5

Leave the call

Call leave() to disconnect. Optionally call destroy() afterward to remove the iframe from the DOM and clean up all event listeners.
await callFrame.leave();

// Optionally remove the iframe entirely:
await callFrame.destroy();

Complete example

A complete call object mode integration. Drop these three files into a project, open index.html, and you have a working video call.
import Daily from '@daily-co/daily-js';

const joinBtn = document.getElementById('join-btn');
const leaveBtn = document.getElementById('leave-btn');
const roomUrlInput = document.getElementById('room-url');

const call = Daily.createCallObject();

function addParticipantDiv(sessionId) {
  const div = document.createElement('div');
  div.id = sessionId;
  document.getElementById('participants').appendChild(div);
}

call
  .on('joined-meeting', (event) => {
    addParticipantDiv(event.participants.local.session_id);
    joinBtn.disabled = true;
    leaveBtn.disabled = false;
  })
  .on('participant-joined', (event) => {
    addParticipantDiv(event.participant.session_id);
  })
  .on('track-started', (event) => {
    const { participant, track, type } = event;
    const id = `${participant.session_id}-${type}`;
    let track_el = document.getElementById(id);
    if (!track_el) {
      let p_el = document.getElementById(participant.session_id);
      if (!p_el) {
        addParticipantDiv(participant.session_id);
        p_el = document.getElementById(participant.session_id);
      }
      track_el = document.createElement(
        track.kind === 'video' ? 'video' : 'audio',
      );
      track_el.id = id;
      track_el.autoplay = true;
      track_el.playsInline = true;
      p_el.appendChild(track_el);
    }
    track_el.srcObject = new MediaStream([track]);
  })
  .on('track-stopped', (event) => {
    document.getElementById(`${event.participant.session_id}-${event.type}`)?.remove();
  })
  .on('participant-left', (event) => {
    document.getElementById(event.participant.session_id)?.remove();
  })
  .on('left-meeting', () => {
    document.getElementById('participants').innerHTML = '';
    joinBtn.disabled = false;
    leaveBtn.disabled = true;
  })
  .on('error', (event) => {
    console.error('Call error:', event.errorMsg);
  });

joinBtn.addEventListener('click', () => {
  call.join({ url: roomUrlInput.value.trim() });
});

leaveBtn.addEventListener('click', () => {
  call.leave();
});

Next steps

Installation

All install methods: npm, yarn, pnpm, and CDN script tag

Call modes

Deep-dive into iframe vs. call object mode trade-offs

Events reference

Full list of events and their payloads

API reference

Complete method and property reference