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

# The call object and provider

> How the Daily call object is created, shared through DailyProvider, and moved through its lifecycle in a React app.

The call object is the heart of every Daily app: it is the `daily-js` instance that joins rooms, sends media, and emits events. [`DailyProvider`](/reference/daily-react/daily-provider) holds it and shares it with your component tree. In most apps, the provider creates and manages the call object for you.

## Let DailyProvider create the call object

The simplest and recommended setup is to pass your room `url` (and any other [factory options](/reference/daily-js/factory-methods/create-call-object) such as `token` or `userName`) directly to [`DailyProvider`](/reference/daily-react/daily-provider). The provider creates the call object, manages its lifecycle, and tears it down for you.

```jsx theme={null}
import { DailyProvider } from '@daily-co/daily-react';

function App() {
  return (
    <DailyProvider url="https://your-domain.daily.co/room-name">
      <Call />
    </DailyProvider>
  );
}
```

This is the right default for most apps: there is no instance to create, store, or clean up, and it is the hardest setup to get wrong.

<Warning>
  The provider recreates the call object whenever a creation prop's value changes (`url`, `token`, and so on), tearing down the current call and resetting all call and error state. These props are compared by value, so re-passing an equivalent object on each render is safe; only an actual value change triggers a rebuild, and nothing defers it while a call is in progress. Treat creation props as stable configuration for the duration of a call.
</Warning>

## Create the call object yourself

Create the instance yourself only when you need direct control over it, for example to access it before the provider mounts, share it outside the provider tree, or create it conditionally. Use [`useCallObject`](/reference/daily-react/use-call-object), then pass it to the provider with the `callObject` prop:

```jsx theme={null}
import { DailyProvider, useCallObject } from '@daily-co/daily-react';

function App() {
  const callObject = useCallObject({
    options: {
      subscribeToTracksAutomatically: true,
    },
  });
  return (
    <DailyProvider callObject={callObject}>
      <Call />
    </DailyProvider>
  );
}
```

<Tip>
  Use [`useCallObject`](/reference/daily-react/use-call-object) rather than calling `Daily.createCallObject()` yourself. It deduplicates instances, which prevents the `Duplicate DailyIframe instances are not allowed` error that surfaces under [React Strict Mode](https://react.dev/reference/react/StrictMode) (where effects intentionally run twice in development).
</Tip>

To delay creation until some condition is met, pass `shouldCreateInstance`:

```jsx theme={null}
// roomUrl comes from your props, router, or state
const callObject = useCallObject({
  shouldCreateInstance: () => Boolean(roomUrl),
});
```

## Access it anywhere with useDaily

Inside the provider, [`useDaily`](/reference/daily-react/use-daily) returns the same [`DailyCall`](/reference/daily-js/daily-call-client) instance. Use it for imperative actions that do not have a dedicated hook:

```jsx theme={null}
import { useDaily } from '@daily-co/daily-react';

function Controls() {
  const daily = useDaily();
  return (
    <>
      <button onClick={() => daily?.setLocalAudio(false)}>Mute me</button>
      <button onClick={() => daily?.setLocalVideo(false)}>Camera off</button>
    </>
  );
}
```

`daily` is `null` until the call object exists, so guard with optional chaining or an early return.

## The call lifecycle

A custom call moves through the same lifecycle as any `daily-js` call. [`useMeetingState`](/reference/daily-react/use-meeting-state) gives you the current stage reactively:

```jsx theme={null}
import { useMeetingState } from '@daily-co/daily-react';

function CallStatus() {
  const meetingState = useMeetingState();
  // 'new' | 'loading' | 'loaded' | 'joining-meeting'
  // | 'joined-meeting' | 'left-meeting' | 'error'
  return <span>Status: {meetingState}</span>;
}
```

### Joining and leaving

There is no `useJoin` hook: joining is an imperative action, so call `join()` on the object from `useDaily`. A mount effect with a cleanup that calls `leave()` is the idiomatic pattern:

```jsx theme={null}
import { useEffect } from 'react';
import { useDaily } from '@daily-co/daily-react';

function Call({ roomUrl, token }) {
  const daily = useDaily();

  useEffect(() => {
    if (!daily) return;
    daily.join({ url: roomUrl, token });
    return () => {
      daily.leave();
    };
  }, [daily, roomUrl, token]);

  return null;
}
```

If you set `url` (and `token`) on `DailyProvider` as recommended above, the call object already has them, so you can call `daily.join()` with no arguments. Pass them to `join()` explicitly only when they are not already on the provider.

The instance is reusable: after `leave()`, the meeting state becomes `left-meeting` and you can `join()` again.

### Handling errors

[`useDailyError`](/reference/daily-react/use-daily-error) exposes the most recent fatal and nonfatal errors as state:

```jsx theme={null}
import { useDailyError } from '@daily-co/daily-react';

function ErrorBanner() {
  const { meetingError, nonFatalError } = useDailyError();
  if (!meetingError && !nonFatalError) return null;
  return <p role="alert">{meetingError?.errorMsg ?? nonFatalError?.errorMsg}</p>;
}
```

<Warning>
  A fatal `error` ejects the participant from the meeting immediately. If you render UI from `meetingError`, do not destroy the call object (or change `DailyProvider`'s creation props, which destroys it internally) until you no longer need the error state.
</Warning>

## Embedding Prebuilt instead of a custom UI

If you want Daily's ready-made UI, create a Prebuilt iframe with [`useCallFrame`](/reference/daily-react/use-call-frame) and pass it to the same provider:

```jsx theme={null}
import { DailyProvider, useCallFrame } from '@daily-co/daily-react';
import { useRef } from 'react';

function PrebuiltApp() {
  const ref = useRef(null);
  const callFrame = useCallFrame({ parentElRef: ref });
  return (
    <DailyProvider callObject={callFrame}>
      <div ref={ref} style={{ height: '100vh' }} />
    </DailyProvider>
  );
}
```

<Note>
  An iframe runs in a separate secure context, so track-level data is not available across the boundary. Hooks that read meeting and participant state still work, but media hooks like [`useMediaTrack`](/reference/daily-react/use-media-track) will not return tracks. For full control over media, use a [call object](#create-the-call-object-yourself) instead.
</Note>

## Next steps

<CardGroup cols={2}>
  <Card title="Working with participants" icon="users" href="/docs/daily-react/docs/participants">
    Read and react to participant state.
  </Card>

  <Card title="Rendering media" icon="video" href="/docs/daily-react/docs/rendering-media">
    Show video and play audio.
  </Card>
</CardGroup>
