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

# Multichannel Transcription

<Note>
  **Supported Languages, Regions, and Models**

  Multichannel transcription is supported for all languages, regions, and
  models.
</Note>

If you have a multichannel audio file with multiple speakers, you can transcribe each of them separately.

The response includes an `audio_channels` property with the number of different channels, and an additional `utterances` property, containing a list of turn-by-turn utterances.

Each utterance contains channel information, starting at 1.

Additionally, each word in the `words` array contains the channel identifier.

## Quickstart

<CodeGroup>
  ```python title="Python SDK" {11}  theme={null}
  import assemblyai as aai

  aai.settings.api_key = "<YOUR_API_KEY>"

  # audio_file = "./local_file.mp3"
  audio_file = "https://assembly.ai/wildfires.mp3"

  config = aai.TranscriptionConfig(
    speech_models=["universal-3-pro", "universal-2"],
    language_detection=True,
    multichannel=True
  )

  transcript = aai.Transcriber(config=config).transcribe(audio_file)

  if transcript.status == "error":
    raise RuntimeError(f"Transcription failed: {transcript.error}")

  for utterance in transcript.utterances:
    print(f"Channel {utterance.speaker}: {utterance.text}")
  ```

  ```python title="Python" {21}  expandable theme={null}
  import requests
  import time

  base_url = "https://api.assemblyai.com"

  headers = {
      "authorization": "<YOUR_API_KEY>"
  }

  with open("./my-audio.mp3", "rb") as f:
    response = requests.post(base_url + "/v2/upload",
                            headers=headers,
                            data=f)

  upload_url = response.json()["upload_url"]

  data = {
      "audio_url": upload_url, # You can also use a URL to an audio or video file on the web
      "speech_models": ["universal-3-pro", "universal-2"],
      "language_detection": True,
      "multichannel": True
  }

  url = base_url + "/v2/transcript"
  response = requests.post(url, json=data, headers=headers)

  transcript_id = response.json()['id']
  polling_endpoint = base_url + "/v2/transcript/" + transcript_id

  while True:
    transcription_result = requests.get(polling_endpoint, headers=headers).json()

    if transcription_result['status'] == 'completed':
      print(f"Transcript ID: {transcript_id}")
      break

    elif transcription_result['status'] == 'error':
      raise RuntimeError(f"Transcription failed: {transcription_result['error']}")

    else:
      time.sleep(3)

  for utterance in transcription_result['utterances']:
    print(f"Channel {utterance['speaker']}: {utterance['text']}")
  ```

  ```javascript title="JavaScript SDK" {14}  expandable theme={null}
  import { AssemblyAI } from "assemblyai";

  const client = new AssemblyAI({
    apiKey: "<YOUR_API_KEY>",
  });

  // const audioFile = './local_file.mp3'
  const audioFile = "https://assembly.ai/wildfires.mp3";

  const params = {
    audio: audioFile,
    speech_models: ["universal-3-pro", "universal-2"],
    language_detection: true,
    multichannel: true,
  };

  const run = async () => {
    const transcript = await client.transcripts.transcribe(params);

    for (const utterance of transcript.utterances ?? []) {
      console.log(`Channel ${utterance.speaker}: ${utterance.text}`);
    }
  };

  run();
  ```

  ```javascript title="JavaScript" {21}  expandable theme={null}
  import fs from "fs-extra";

  const baseUrl = "https://api.assemblyai.com";

  const headers = {
    authorization: "<YOUR_API_KEY>",
  };

  const path = "./my-audio.mp3";
  const audioData = await fs.readFile(path);
  let res = await fetch(`${baseUrl}/v2/upload`, {
    method: "POST",
    headers,
    body: audioData,
  });
  if (!res.ok) throw new Error(`Error: ${res.status}`);
  const uploadResponse = await res.json();
  const uploadUrl = uploadResponse.upload_url;

  const data = {
    audio_url: uploadUrl, // You can also use a URL to an audio or video file on the web
    speech_models: ["universal-3-pro", "universal-2"],
    language_detection: true,
    multichannel: true,
  };

  const url = `${baseUrl}/v2/transcript`;
  res = await fetch(url, {
    method: "POST",
    headers: { ...headers, "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });
  if (!res.ok) throw new Error(`Error: ${res.status}`);
  const response = await res.json();

  const transcriptId = response.id;
  const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;

  while (true) {
    res = await fetch(pollingEndpoint, { headers });
    if (!res.ok) throw new Error(`Error: ${res.status}`);
    const transcriptionResult = await res.json();

    if (transcriptionResult.status === "completed") {
      for (const utterance of transcriptionResult.utterances) {
        console.log(`Channel ${utterance.speaker}: ${utterance.text}`);
      }
      break;
    } else if (transcriptionResult.status === "error") {
      throw new Error(`Transcription failed: ${transcriptionResult.error}`);
    } else {
      await new Promise((resolve) => setTimeout(resolve, 3000));
    }
  }
  ```
</CodeGroup>

<Note>
  Multichannel audio increases the transcription time by approximately 40%.
</Note>

## Per-channel diarization

If you have a multichannel audio file where individual channels may contain multiple speakers, you can combine `multichannel` and `speaker_labels` to perform diarization within each channel.

<Warning>
  When using `multichannel` with `speaker_labels`, the `speaker_options` parameters (`min_speakers_expected` and `max_speakers_expected`) are applied **per channel**, not globally across the entire file. For example, setting `min_speakers_expected: 5` and `max_speakers_expected: 7` on a 5-channel file means the model will find 5–7 speakers on *each* channel, resulting in 25–35 total speakers. Adjust your speaker options accordingly when using multichannel transcription.
</Warning>

When both parameters are enabled:

* Channels are labeled numerically (1, 2, 3, etc.)
* Speakers within each channel are labeled alphabetically (A, B, C, etc.)
* The combined speaker label format is `{channel}{speaker}` (e.g., "1A", "1B", "2A")

For example, if channel 1 has two speakers and channel 2 has one speaker, the labels would be:

* First speaker on channel 1: `1A`
* Second speaker on channel 1: `1B`
* First speaker on channel 2: `2A`

<CodeGroup>
  ```python title="Python SDK" {11-12} expandable theme={null}
  import assemblyai as aai

  aai.settings.api_key = "<YOUR_API_KEY>"

  # audio_file = "./local_file.mp3"
  audio_file = "https://assembly.ai/wildfires.mp3"

  config = aai.TranscriptionConfig(
    speech_models=["universal-3-pro", "universal-2"],
    language_detection=True,
    multichannel=True,
    speaker_labels=True
  )

  transcript = aai.Transcriber(config=config).transcribe(audio_file)

  if transcript.status == "error":
    raise RuntimeError(f"Transcription failed: {transcript.error}")

  for utterance in transcript.utterances:
    print(f"Speaker {utterance.speaker}: {utterance.text}")
  ```

  ```python title="Python" {21-22} expandable theme={null}
  import requests
  import time

  base_url = "https://api.assemblyai.com"

  headers = {
      "authorization": "<YOUR_API_KEY>"
  }

  with open("./my-audio.mp3", "rb") as f:
    response = requests.post(base_url + "/v2/upload",
                            headers=headers,
                            data=f)

  upload_url = response.json()["upload_url"]

  data = {
      "audio_url": upload_url, # You can also use a URL to an audio or video file on the web
      "speech_models": ["universal-3-pro", "universal-2"],
      "language_detection": True,
      "multichannel": True,
      "speaker_labels": True
  }

  url = base_url + "/v2/transcript"
  response = requests.post(url, json=data, headers=headers)

  transcript_id = response.json()['id']
  polling_endpoint = base_url + "/v2/transcript/" + transcript_id

  while True:
    transcription_result = requests.get(polling_endpoint, headers=headers).json()

    if transcription_result['status'] == 'completed':
      print(f"Transcript ID: {transcript_id}")
      break

    elif transcription_result['status'] == 'error':
      raise RuntimeError(f"Transcription failed: {transcription_result['error']}")

    else:
      time.sleep(3)

  for utterance in transcription_result['utterances']:
    print(f"Speaker {utterance['speaker']}: {utterance['text']}")
  ```

  ```javascript title="JavaScript SDK" {14-15} expandable theme={null}
  import { AssemblyAI } from "assemblyai";

  const client = new AssemblyAI({
    apiKey: "<YOUR_API_KEY>",
  });

  // const audioFile = './local_file.mp3'
  const audioFile = "https://assembly.ai/wildfires.mp3";

  const params = {
    audio: audioFile,
    speech_models: ["universal-3-pro", "universal-2"],
    language_detection: true,
    multichannel: true,
    speaker_labels: true,
  };

  const run = async () => {
    const transcript = await client.transcripts.transcribe(params);

    for (const utterance of transcript.utterances ?? []) {
      console.log(`Speaker ${utterance.speaker}: ${utterance.text}`);
    }
  };

  run();
  ```

  ```javascript title="JavaScript" {21-22} expandable theme={null}
  import fs from "fs-extra";

  const baseUrl = "https://api.assemblyai.com";

  const headers = {
    authorization: "<YOUR_API_KEY>",
  };

  const path = "./my-audio.mp3";
  const audioData = await fs.readFile(path);
  let res = await fetch(`${baseUrl}/v2/upload`, {
    method: "POST",
    headers,
    body: audioData,
  });
  if (!res.ok) throw new Error(`Error: ${res.status}`);
  const uploadResponse = await res.json();
  const uploadUrl = uploadResponse.upload_url;

  const data = {
    audio_url: uploadUrl, // You can also use a URL to an audio or video file on the web
    speech_models: ["universal-3-pro", "universal-2"],
    language_detection: true,
    multichannel: true,
    speaker_labels: true,
  };

  const url = `${baseUrl}/v2/transcript`;
  res = await fetch(url, {
    method: "POST",
    headers: { ...headers, "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });
  if (!res.ok) throw new Error(`Error: ${res.status}`);
  const response = await res.json();

  const transcriptId = response.id;
  const pollingEndpoint = `${baseUrl}/v2/transcript/${transcriptId}`;

  while (true) {
    res = await fetch(pollingEndpoint, { headers });
    if (!res.ok) throw new Error(`Error: ${res.status}`);
    const transcriptionResult = await res.json();

    if (transcriptionResult.status === "completed") {
      for (const utterance of transcriptionResult.utterances) {
        console.log(`Speaker ${utterance.speaker}: ${utterance.text}`);
      }
      break;
    } else if (transcriptionResult.status === "error") {
      throw new Error(`Transcription failed: ${transcriptionResult.error}`);
    } else {
      await new Promise((resolve) => setTimeout(resolve, 3000));
    }
  }
  ```
</CodeGroup>
