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

# Active speaker and audio levels

> Highlight whoever is talking with useActiveSpeakerId and build volume meters with useAudioLevelObserver.

Showing who is speaking makes a call feel alive. Daily React gives you two tools: [`useActiveSpeakerId`](/reference/daily-react/use-active-speaker-id) for the current speaker, and [`useAudioLevelObserver`](/reference/daily-react/use-audio-level-observer) for continuous volume.

## Highlight the active speaker

[`useActiveSpeakerId`](/reference/daily-react/use-active-speaker-id) returns the session ID of the participant Daily considers the active speaker, or `null` when nobody has spoken:

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

function Tile({ sessionId }) {
  const activeSpeakerId = useActiveSpeakerId();
  const isSpeaking = sessionId === activeSpeakerId;
  return (
    <div style={{ outline: isSpeaking ? '3px solid limegreen' : 'none' }}>
      <DailyVideo sessionId={sessionId} type="video" />
    </div>
  );
}
```

### Spotlight layouts

For a spotlight that follows the speaker, render the active speaker's video directly. Pass `ignoreLocal` so your own voice does not steal the spotlight:

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

function Spotlight() {
  const activeSpeakerId = useActiveSpeakerId({ ignoreLocal: true });
  if (!activeSpeakerId) return <p>Waiting for someone to speak…</p>;
  return <DailyVideo sessionId={activeSpeakerId} type="video" fit="cover" />;
}
```

Pass a `filter` callback to restrict which participants can become the active speaker, for example to spotlight only presenters:

```jsx theme={null}
const activeSpeakerId = useActiveSpeakerId({
  filter: (sessionId) => presenterIds.includes(sessionId),
});
```

## Build a volume meter

The active speaker is a coarse, on/off signal. For a continuous volume meter, [`useAudioLevelObserver`](/reference/daily-react/use-audio-level-observer) calls you back with a number between 0 and 1 as a participant's volume changes:

```jsx theme={null}
import { useAudioLevelObserver, useLocalSessionId } from '@daily-co/daily-react';
import { useCallback, useRef } from 'react';

function MicMeter() {
  const localSessionId = useLocalSessionId();
  const barRef = useRef(null);

  useAudioLevelObserver(
    localSessionId,
    useCallback((volume) => {
      // Drive the DOM directly; avoid setState on every frame.
      if (barRef.current) barRef.current.style.transform = `scaleY(${Math.max(0.05, volume)})`;
    }, [])
  );

  return <div ref={barRef} style={{ height: 40, width: 8, background: 'limegreen', transformOrigin: 'bottom' }} />;
}
```

<Tip>
  Volume fires frequently. Write to a ref and mutate the DOM (as above) rather than calling `setState` on every change, which would re-render the component dozens of times a second. The callback must be memoized with `useCallback`, like all Daily React event callbacks.
</Tip>

Pass `interval` (minimum 100ms) to control how often the callback fires, and `onError` to handle browsers where the observer is unavailable.

<Note>
  The older `useAudioLevel` hook (which took a raw `MediaStreamTrack`) is **deprecated as of 0.20.0**. Use `useAudioLevelObserver` with a `sessionId` instead.
</Note>

## Speaking indicator, complete

A muted-aware speaking dot for a tile:

```jsx theme={null}
import { useCallback, useRef } from 'react';
import { useAudioLevelObserver, useMediaTrack } from '@daily-co/daily-react';

function SpeakingDot({ sessionId }) {
  const audio = useMediaTrack(sessionId, 'audio');
  const dotRef = useRef(null);

  useAudioLevelObserver(
    sessionId,
    useCallback((volume) => {
      if (dotRef.current) dotRef.current.style.opacity = String(Math.min(1, volume * 4));
    }, [])
  );

  if (audio.isOff) return <span>🔇</span>;
  return <span ref={dotRef} style={{ opacity: 0 }}>🟢</span>;
}
```

## Next steps

<CardGroup cols={2}>
  <Card title="Rendering media" icon="video" href="/docs/daily-react/docs/rendering-media">
    The video and audio components.
  </Card>

  <Card title="Working with participants" icon="users" href="/docs/daily-react/docs/participants">
    Read more participant state.
  </Card>
</CardGroup>
