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

# Real-Time Transcription

> Transcribe speech in Daily calls in real time using Deepgram, with per-participant filtering, profanity control, and raw response access.

<Badge color="blue">Paid plans only</Badge>

<Card title="Transcription overview" icon="closed-captioning" href="/docs/guides/features/transcription">
  New to Daily transcription? Start here — covers real-time vs. post-call transcription, pricing, permissions, and transcript storage.
</Card>

Daily's transcription feature streams speech-to-text output to all participants in a call. It is powered by [Deepgram](https://deepgram.com) and supports a wide range of languages, models, and configuration options.

## Transcription permissions

Only meeting owners and participants with `canAdmin: 'transcription'` can start or stop transcription. See [Permissions](/docs/guides/features/transcription#permissions) in the overview for how to grant this.

## Transcript storage

By default, transcripts are ephemeral — participants receive `transcription-message` events but nothing is persisted. To save transcripts as WebVTT files, enable `enable_transcription_storage` at the room or domain level. See [Storage](/docs/guides/features/transcription#storage) in the overview for setup details, including custom S3 configuration for HIPAA use cases.

## Starting transcription

[`startTranscription()`](/reference/daily-js/instance-methods/start-transcription) starts a transcription session. All options are optional — call it with no arguments to use Deepgram defaults.

```javascript theme={null}
// Start with Deepgram defaults
call.startTranscription();

// Start with explicit language and model
call.startTranscription({
  language: 'en',
  model: 'nova-2',
  punctuate: true,
  profanity_filter: false,
});
```

<Tip>
  Check [Deepgram's language and model overview](https://developers.deepgram.com/docs/models-languages-overview) for the `model`/`language` combination that works best for your use case.
</Tip>

See [`startTranscription()`](/reference/daily-js/instance-methods/start-transcription) for the full list of options.

## Handling transcription messages

Listen to [`transcription-message`](/reference/daily-js/events/transcription-events#transcription-message) to receive transcript segments in real time:

```javascript theme={null}
call.on('transcription-message', (event) => {
  console.log('[transcript]', event.text);
  console.log('  participant:', event.participantId);
  console.log('  timestamp:', event.timestamp);
  console.log('  track type:', event.trackType); // 'cam-audio' | 'screen-audio' | ...
  console.log('  instance:', event.instanceId);

  if (event.rawResponse) {
    // Full Deepgram response — available when includeRawResponse: true
    console.log('  raw:', event.rawResponse);
  }
});
```

## Updating transcription

Use [`updateTranscription()`](/reference/daily-js/instance-methods/update-transcription) to change which participants are being transcribed while transcription is running:

```javascript theme={null}
// Transcribe only the presenter
call.updateTranscription({
  participants: [presenterSessionId],
});

// Restore transcription for everyone
call.updateTranscription({
  participants: null,
});
```

Note that participants who join after transcription starts are not automatically added — use `updateTranscription()` to add them.

## Stopping transcription

[`stopTranscription()`](/reference/daily-js/instance-methods/stop-transcription) ends a transcription session. If storage is enabled, the final transcript file is written at this point.

```javascript theme={null}
// Stop the default transcription instance
call.stopTranscription();

// Stop a named instance
call.stopTranscription({ instanceId: 'primary' });
```

## Events

Full payload details are in the [transcription events reference](/reference/daily-js/events/transcription-events).

```javascript theme={null}
call.on('transcription-started', ({ instanceId, language, model, startedBy }) => {
  console.log(`Transcription started (${model}/${language})`);
  captionsIndicator.hidden = false;
});

call.on('transcription-stopped', ({ instanceId, updatedBy }) => {
  captionsIndicator.hidden = true;
});

call.on('transcription-error', ({ instanceId, errorMsg }) => {
  console.error('Transcription error:', errorMsg);
});
```

## Post-call transcription

To transcribe a recording after a call ends, use the [Batch Processor API](/reference/rest-api/batch-processor/index). See [Post-call transcription](/docs/guides/features/transcription#post-call-transcription) in the overview for details.

## Complete example

<Steps>
  <Step title="Start transcription when joining">
    ```javascript theme={null}
    const call = Daily.createCallObject();

    call.on('joined-meeting', () => {
      call.startTranscription({
        language: 'en',
        model: 'nova-2',
        punctuate: true,
      });
    });

    await call.join({ url: 'https://your-domain.daily.co/room' });
    ```
  </Step>

  <Step title="Display captions in real time">
    ```javascript theme={null}
    const captionsDiv = document.getElementById('captions');

    call.on('transcription-message', ({ participantId, text }) => {
      const name =
        call.participants()[participantId]?.user_name ||
        participantId.slice(0, 8);

      const line = document.createElement('p');
      line.textContent = `${name}: ${text}`;
      captionsDiv.appendChild(line);
      captionsDiv.scrollTop = captionsDiv.scrollHeight;
    });
    ```
  </Step>

  <Step title="Handle lifecycle events">
    ```javascript theme={null}
    call.on('transcription-started', ({ language, model }) => {
      document.getElementById('captions-status').textContent =
        `Live captions on (${model}/${language})`;
    });

    call.on('transcription-stopped', () => {
      document.getElementById('captions-status').textContent = '';
    });

    call.on('transcription-error', ({ errorMsg }) => {
      console.error('Transcription error:', errorMsg);
    });
    ```
  </Step>

  <Step title="Stop transcription on leave">
    ```javascript theme={null}
    document.getElementById('leave').onclick = async () => {
      call.stopTranscription();
      await call.leave();
    };
    ```
  </Step>
</Steps>
