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

# testCallQuality()

> Runs a pre-call network quality test and returns connection quality results.

`testCallQuality()`

<Badge color="red">{"✗"} Prebuilt</Badge> <Badge color="green">{"✓"} Custom</Badge>

<Note>
  Prebuilt runs this test automatically as part of its prejoin UI.
</Note>

Assesses a user's network performance before joining a Daily call. The method connects to a Daily room and streams video to Daily's infrastructure for up to 30 seconds, collecting outbound WebRTC stats. Results represent the average values over the test period.

Must be called after [`preAuth()`](/reference/daily-js/instance-methods/pre-auth) or [`startCamera()`](/reference/daily-js/instance-methods/start-camera) and before [`join()`](/reference/daily-js/instance-methods/join).

If [Adaptive Bitrate](/docs/guides/architecture-and-monitoring/adaptive-bitrate) is enabled (default for 1:1 calls), results are stored on the call instance and used at join time to initialize the highest simulcast layer appropriately.

## Return value

Returns `Promise<DailyCallQualityTestResults>`.

<ResponseField name="result" type="'good' | 'warning' | 'bad' | 'aborted' | 'failed'">
  Overall connection quality verdict:

  * `'good'` — `avgSendPacketLoss` \< 5%, `maxRoundTripTime` \< 300ms, `avgSendBitsPerSecond` ≥ 1,100,000
  * `'warning'` — `avgSendPacketLoss` 5–10%, `maxRoundTripTime` 300–600ms, `avgSendBitsPerSecond` 700,000–1,100,000
  * `'bad'` — `avgSendPacketLoss` ≥ 10%, `maxRoundTripTime` ≥ 600ms, `avgSendBitsPerSecond` \< 700,000
  * `'failed'` — test meeting ended in error; error details are included in the result
  * `'aborted'` — test stopped before data gathering started (e.g. `join()` or `stopTestCallQuality()` called too quickly)
</ResponseField>

<ResponseField name="secondsElapsed" type="number">
  Seconds over which data was collected (up to 30). Timer starts after the test has joined a call and begun sending data.
</ResponseField>

<ResponseField name="data" type="object">
  Underlying stats used to determine the result. All averages use an exponential moving average biased toward the most recent data.

  * `maxRoundTripTime` (seconds) — maximum [`currentRoundTripTime`](https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidatePairStats/currentRoundTripTime) sampled
  * `avgRoundTripTime` (seconds) — average `currentRoundTripTime`
  * `avgSendPacketLoss` (percentage) — average outbound packet loss.  Depending on the browser, this is based off either [fractionLost](https://w3c.github.io/webrtc-stats/#dom-rtcremoteinboundrtpstreamstats-fractionlost) or [packetsLost](https://w3c.github.io/webrtc-stats/#dom-rtcreceivedrtpstreamstats-packetslost)/ [packetsSent](https://w3c.github.io/webrtc-stats/#dom-rtctransportstats-packetssent).
  * `avgAvailableOutgoingBitrate` (bps) — average [`availableOutgoingBitrate`](https://w3c.github.io/webrtc-stats/#dom-rtcicecandidatepairstats-availableoutgoingbitrate) (not available on Firefox)
  * `avgSendBitsPerSecond` (bps) — average outbound bitrate (delta [`bytesSent`](https://www.w3.org/TR/webrtc-stats/#dom-rtcsentrtpstreamstats-bytessent) / delta time)
</ResponseField>

<ResponseField name="id" type="string">
  Session ID of the test call. Test calls use a private domain and do not appear in your account dashboard.
</ResponseField>

<ResponseField name="errorMsg" type="string">
  Human-readable error message. Only present when `result === 'failed'`.
</ResponseField>

<ResponseField name="error" type="DailyFatalErrorObject">
  Structured error object with `type`, `msg`, and `details`. Only present when `result === 'failed'` and error details are available.
</ResponseField>

## Example

```javascript theme={null}
call.testCallQuality().then((results) => {
  switch (results.result) {
    case 'aborted':
      return console.log('Test aborted before any data was gathered.');
    case 'failed':
      return console.warn('Test ended in error.');
    case 'bad':
      return console.warn('Internet connection is bad. Try a different network.');
    case 'warning':
      return console.warn('Video and audio might be choppy.');
    case 'good':
    default:
      return console.log('Internet connection is good.');
  }
});
```

<Tip>
  If the test returns `'bad'` and adaptive bitrate is disabled or the client is on Firefox, consider calling [`updateSendSettings()`](/reference/daily-js/instance-methods/update-send-settings) with `'bandwidth-optimized'` before joining.
</Tip>

### Example failure result

```json theme={null}
{
  "result": "failed",
  "secondsElapsed": 29,
  "errorMsg": "signaling connection failed",
  "error": {
    "type": "connection-error",
    "msg": "signaling connection failed",
    "details": {
      "uri": "wss://ip-10-82-1-65-us-west-2.wss.daily.co:443",
      "sourceError": {
        "message": "WebSocket connection error",
        "name": "WEBSOCKET_ERROR",
        "code": 1006,
        "reason": ""
      }
    }
  },
  "id": "1e30b5fe-b566-46e3-a48d-b8ab762a6673"
}
```

## See also

<CardGroup>
  <Card title="Methods" icon="code" iconType="solid">
    * [stopTestCallQuality()](/reference/daily-js/instance-methods/stop-test-call-quality)
    * [testNetworkConnectivity()](/reference/daily-js/instance-methods/test-network-connectivity)
    * [testWebsocketConnectivity()](/reference/daily-js/instance-methods/test-websocket-connectivity)
    * [getNetworkStats()](/reference/daily-js/instance-methods/get-network-stats)
  </Card>

  <Card title="Events" icon="bolt" iconType="solid">
    * [test-completed](/reference/daily-js/events/network-events#test-completed)
  </Card>
</CardGroup>
