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

# Handle diarized transcripts

> Order and render speaker-attributed /streams segments in true chronological order

<iframe className="w-full aspect-video rounded-xl" src="https://www.youtube.com/embed/d6WKOaS9_Ts?start=651&end=680" title="Handle Diarized Transcripts — walkthrough" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowFullScreen />

<Info>
  **Follow along with the runnable example.** This guide walks through the [diarized ambient example](https://github.com/corticph/corti-examples/tree/main/sdk/typescript/applets/src/applets/ambient-diarized) in `corti-examples` — bootstrap your build from it or use it as reference.
</Info>

When [diarization](/stt/diarization) is enabled on [`/streams`](/stt/streams), the server attributes speech to distinct speakers. Because each speaker's segments are finalized independently, `transcript` messages **do not arrive in chronological order** — and each message carries an **array** of segments, not a single one. Your client is responsible for ordering them and grouping by speaker before rendering.

This guide shows the client handling using the [Ambient Web Component](/sdk/ambient/overview). It's the ambient counterpart to [dictation text insertion](/stt/guides/dictation-text-insertion) — but the concern here is purely **ordering**, not interim-vs-final reconciliation.

<Note>
  For the ordering **rules** — the `time`/`speakerId`/`channel` fields and why arrival order is unreliable — see [Diarized Transcript Handling](/stt/best-practices-diarized-transcripts). This page focuses on wiring them into your app.
</Note>

***

## Configure a diarized stream

Enable `isDiarization` to separate speakers within a single mono stream. For fixed per-channel roles instead, use `isMultichannel` with `participants` — the two are mutually exclusive. See the [diarized ambient example](https://github.com/corticph/corti-examples/tree/main/sdk/typescript/applets/src/applets/ambient-diarized) in `corti-examples` for the full stream configuration.

***

## Merge each message in order

Each `transcript` event carries an **array** of final segments. Merge every message into a running list keyed by segment identity, and keep it sorted by `time.start` (tie-break `time.end`) — never append in arrival order.

```ts title="JavaScript" theme={null}
// A segment has no id, so key on its (start, end, speaker) tuple — repeated
// messages then update in place instead of duplicating.
const segmentKey = (s) => `${s.time.start}:${s.time.end}:${s.speakerId}`;

function mergeDiarizedSegments(current, incoming) {
  const byKey = new Map(current.map((s) => [segmentKey(s), s]));
  for (const s of incoming) byKey.set(segmentKey(s), s);
  return [...byKey.values()].sort(
    (a, b) => a.time.start - b.time.start || a.time.end - b.time.end,
  );
}
```

Call `mergeDiarizedSegments` from your `transcript` event handler, passing `e.detail?.data` (the segment array) as `incoming`.

<Check>
  Only **final** segments are sent on `/streams` (there are no interim results), so there is no interim-vs-final dedup to do — just ordering and de-duplication by segment identity.
</Check>

***

## Group by speaker

To render speaker-labelled blocks, collapse the ordered list into consecutive runs by speaker — so one speaker's words are never interleaved into another's.

```ts title="JavaScript" theme={null}
function groupBySpeakerRuns(segments) {
  const groups = [];
  for (const seg of segments) {
    const last = groups[groups.length - 1];
    if (last && last.speakerId === seg.speakerId) {
      last.segments.push(seg);
    } else {
      groups.push({ speakerId: seg.speakerId, channel: seg.participant?.channel, segments: [seg] });
    }
  }
  return groups;
}
```

<Note>
  `speakerId` and `participant.channel` are independent — diarization separates speakers *within* a stream, while the channel reflects audio routing. Don't assume a fixed mapping between them, and remember `speakerId` is `-1` when diarization is off.
</Note>

***

## Next steps

<CardGroup cols={2}>
  <Card title="Diarized Transcript Handling" icon="users" href="/stt/best-practices-diarized-transcripts">
    The ordering rules and segment fields behind this integration.
  </Card>

  <Card title="Ambient Web Component" icon="waveform-lines" href="/sdk/ambient/overview">
    The drop-in component for real-time multi-speaker ambient streaming.
  </Card>

  <Card title="Example code" icon="github" href="https://github.com/corticph/corti-examples/tree/main/sdk/typescript/applets/src/applets/ambient-diarized">
    The complete, runnable diarized ambient example in `corti-examples`.
  </Card>
</CardGroup>

<Note>Please [contact us](mailto:help@corti.ai) for help or questions.</Note>
