> ## Documentation Index
> Fetch the complete documentation index at: https://docs.daily.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Get a working video call running in under 5 minutes with daily-js.

<Note>
  You need a Daily account and a room URL to complete this guide. Create a free account at [daily.co](https://www.daily.co) and create a room from the dashboard to get a URL in the format `https://your-domain.daily.co/room-name`.
</Note>

## 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.

<Tabs>
  <Tab title="Iframe mode (Prebuilt UI)">
    <Steps>
      <Step title="Install the package">
        Add `@daily-co/daily-js` to your project:

        <CodeGroup>
          ```bash npm theme={null}
          npm install @daily-co/daily-js
          ```

          ```bash yarn theme={null}
          yarn add @daily-co/daily-js
          ```

          ```bash pnpm theme={null}
          pnpm add @daily-co/daily-js
          ```
        </CodeGroup>
      </Step>

      <Step title="Create a call frame">
        Import `DailyIframe` and call `createFrame()`. This creates an `<iframe>` element and appends it to `document.body` by default.

        ```javascript theme={null}
        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:

        ```javascript theme={null}
        const container = document.getElementById('call-container');
        const callFrame = Daily.createFrame(container);
        ```

        You can also pass style options:

        ```javascript theme={null}
        const callFrame = Daily.createFrame({
          iframeStyle: {
            position: 'fixed',
            width: '100%',
            height: '100%',
            top: 0,
            left: 0,
            border: 0,
          },
        });
        ```
      </Step>

      <Step title="Join a room">
        Call `join()` with your room URL. This returns a promise that resolves once you have entered the meeting.

        ```javascript theme={null}
        await callFrame.join({ url: 'https://your-domain.daily.co/room-name' });
        ```
      </Step>

      <Step title="Listen for events">
        Subscribe to call events using `.on()`. The `joined-meeting` event fires once you are connected and includes the current participants.

        ```javascript theme={null}
        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);
          });
        ```
      </Step>

      <Step title="Leave the call">
        Call `leave()` to disconnect. Optionally call `destroy()` afterward to remove the iframe from the DOM and clean up all event listeners.

        ```javascript theme={null}
        await callFrame.leave();

        // Optionally remove the iframe entirely:
        await callFrame.destroy();
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Call object mode (Custom UI)">
    <Steps>
      <Step title="Install the package">
        Add `@daily-co/daily-js` to your project:

        <CodeGroup>
          ```bash npm theme={null}
          npm install @daily-co/daily-js
          ```

          ```bash yarn theme={null}
          yarn add @daily-co/daily-js
          ```

          ```bash pnpm theme={null}
          pnpm add @daily-co/daily-js
          ```
        </CodeGroup>
      </Step>

      <Step title="Create a call object">
        `createCallObject()` returns a headless call instance with no iframe or built-in UI. All audio and video rendering is your responsibility.

        ```javascript theme={null}
        import Daily from '@daily-co/daily-js';

        const call = Daily.createCallObject();
        ```

        You can pass options at construction time:

        ```javascript theme={null}
        const call = Daily.createCallObject({
          startVideoOff: true,
          startAudioOff: false,
        });
        ```
      </Step>

      <Step title="Join a room">
        Call `join()` with your room URL:

        ```javascript theme={null}
        await call.join({ url: 'https://your-domain.daily.co/room-name' });
        ```
      </Step>

      <Step title="Listen for events and render tracks">
        Subscribe to events to drive your UI. Each participant gets a `<div>` when they join; tracks are appended to it as they start.

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

        call
          .on('joined-meeting', (event) => {
            // Set up a div for the local participant
            addParticipantDiv(event.participants.local.session_id);
          })
          .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 el = document.getElementById(id);
            if (!el) {
              el = document.createElement(track.kind === 'video' ? 'video' : 'audio');
              el.id = id;
              el.autoplay = true;
              el.playsInline = true;
              document.getElementById(participant.session_id).appendChild(el);
            }
            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('error', (event) => {
            console.error('Call error:', event.errorMsg);
          });
        ```
      </Step>

      <Step title="Leave the call">
        ```javascript theme={null}
        await call.leave();

        // Optionally destroy the instance when you're fully done with it:
        await call.destroy();
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

## 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.

<CodeGroup>
  ```javascript call.js theme={null}
  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();
  });
  ```

  ```html index.html theme={null}
  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <title>Daily call</title>
      <link rel="stylesheet" href="style.css" />
    </head>
    <body>
      <div id="controls">
        <input id="room-url" type="text" placeholder="https://your-domain.daily.co/room-name" />
        <button id="join-btn">Join</button>
        <button id="leave-btn" disabled>Leave</button>
      </div>
      <div id="participants"></div>
      <script type="module" src="call.js"></script>
    </body>
  </html>
  ```

  ```css style.css theme={null}
  #controls {
    display: flex;
    gap: 0.5rem;
    padding: 1rem;
  }

  #room-url {
    flex: 1;
    padding: 0.4rem 0.6rem;
  }

  #participants {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    padding: 1rem;
  }

  #participants > div {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }

  video {
    width: 320px;
    height: 240px;
    background: #000;
    border-radius: 4px;
  }
  ```
</CodeGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Installation" icon="wrench" href="/docs/daily-js/installation">
    All install methods: npm, yarn, pnpm, and CDN script tag
  </Card>

  <Card title="Call modes" icon="grid-2" href="/docs/daily-js/concepts/call-modes">
    Deep-dive into iframe vs. call object mode trade-offs
  </Card>

  <Card title="Events reference" icon="bell" href="/reference/daily-js/events/index">
    Full list of events and their payloads
  </Card>

  <Card title="API reference" icon="code" href="/reference/daily-js/factory-methods/create-call-object">
    Complete method and property reference
  </Card>
</CardGroup>
