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

# Reducing Join Latency

> Strategies to reduce perceived and actual latency when starting Tavus conversations

When starting a Tavus conversation, reducing both perceived and actual latency creates a smoother, more professional user experience. Below are two key strategies to optimize startup latency.

## 1. Add a Hair Check

The goal is to wait until the replica has actually joined before dropping the user into the live room, so the experience feels instant instead of "loading / awkward silence."

Tavus provides a ready-made Hair Check block you can plug into your application. The Hair Check component shows a pre-call interface where users can test and configure their audio/video devices while the replica joins the room in the background.

**Waiting for the replica to join:**

Before transitioning from the Hair Check screen to the live conversation, wait for the `participant-joined` event from Daily. In a Tavus CVI one-to-one conversation, any participant that joins that is not the 'local' participant is the replica.

```javascript theme={null}
// Using Daily participant-joined event
callObject.on('participant-joined', (event) => {
  const participant = event.participant;
  // Filter out 'local' participant - any non-local participant is the replica
  if (participant.id !== 'local') {
    // Replica has joined, safe to transition user to conversation
    setScreen('call');
  }
});
```

You can also use the `participant.user_name` property to identify the replica, or alternatively listen for the `system.replica_joined` webhook callback if you've set a `callback_url` when creating the conversation. For webhook-based approach, see the [Webhooks and Callbacks documentation](/sections/webhooks-and-callbacks) for details on the `system.replica_joined` event.

Additionally, `system.replica_joined` is also broadcast as a Tavus app-event over Daily's data channel. You can listen for Daily `app-message` events and check `event_type === "system.replica_joined"` if you prefer in-call event handling rather than webhooks.

**Benefits:**

* Users see an active interface instead of a loading screen
* Device permissions are handled before joining
* The replica has time to fully join before the user enters
* Creates a seamless, instant-feeling transition

**Implementation:**

```bash theme={null}
npx @tavus/cvi-ui@latest add hair-check-01
```

```tsx theme={null}
import { HairCheck } from './components/cvi/components/hair-check';

<HairCheck
  isJoinBtnLoading={isLoading}
  onJoin={handleJoinCall}
  onCancel={handleCancel}
/>
```

**Example Implementation:**

You can try the Hair Check experience and clone the complete working example from the [CVI UI Haircheck Conversation Example](https://github.com/Tavus-Engineering/tavus-examples/tree/main/examples/cvi-ui-haircheck-conversation). The example includes both the Hair Check and Conversation components set up together.

For complete setup instructions and component details, see the [Hair Check block documentation](/sections/conversational-video-interface/component-library/blocks#hair-check).

***

## 2. Add a Network Check for Proactive Troubleshooting

Daily provides network connectivity test components you can run before joining to detect common issues (bandwidth, network connectivity, etc.).

### `testCallQuality()` (Recommended)

The most comprehensive pre-call test. It automatically connects to a Daily room, streams video, and collects outbound WebRTC stats for up to 30 seconds.

**Returns:**

* `"good"`: Network conditions are optimal
* `"bad"`: Network conditions are poor
* `"warning"`: Network conditions may cause issues
* `"aborted"`: Test was interrupted
* `"failed"`: Test failed to complete

**Usage:**

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

const callObject = DailyIframe.createCallObject();

// Run test before joining
const result = await callObject.testCallQuality();

if (result.result === 'good') {
  // Proceed with joining the conversation
  await callObject.join({ url: conversationUrl });
} else if (result.result === 'bad' || result.result === 'warning') {
  // Display user-facing message about poor connection
  showConnectionWarning('Your connection quality may affect your experience. Consider improving your network connection.');
  // Optionally proceed anyway or block joining
  await callObject.join({ url: conversationUrl });
} else {
  // Handle failed or aborted tests
  console.warn('Network quality check:', result.result);
}
```

**User messaging:**

Use the test results to inform users about their connection quality. When the result is `"bad"` or `"warning"`, display a message letting them know their connection is poor and may affect their experience. This helps set expectations and allows users to improve their network before joining.

**Benefits:**

* Detects bandwidth issues before the user joins
* Identifies network connectivity problems
* Provides actionable feedback about network conditions
* Allows you to set user expectations about connection quality
* Reduces failed connection attempts and user frustration

For more details, see the [Daily testCallQuality documentation](https://docs.daily.co/reference/daily-js/instance-methods/test-call-quality).

***

## Summary

Combining these two strategies significantly improves the startup experience:

1. **Hair Check** - Masks loading time with an active interface
2. **Network Testing** - Proactively identifies and handles connectivity issues

Together, these approaches reduce both perceived latency (what users experience) and actual latency (technical performance), creating a smoother, more professional conversation startup.
