Article: Working with Timestamps, Utterances, and Speaker Diarization in Deepgram Author: Stephen Oladele
Date: Sep 22, 2025
Read Time: 15 min

🎥 Video Overview

⏩ TL;DR

  • STT is the baseline; the value is in the metadata. Deepgram returns timestamped transcripts with utterances and speaker diarization so you can answer who said what, when—reliably.
  • Turn utterances=true, diarize=true, and smart_format=true on Deepgram’s STT API to get structured, context-aware results out of the box.
  • With this, you can power search, segmentation, QA checks, and analytics (talk time, interruptions, and silence).

Introduction

Speech-to-text (STT) isn’t just about words—it’s about context. In real conversations, who spoke, when they spoke, and how long they spoke often matter as much as what they said. A flat, speakerless transcript throws away that structure.

Deepgram’s speaker diarization STT and utterance segmentation give you timestamped transcripts that preserve conversational context:

  • Utterances: semantically coherent segments with start/end times.
  • Speaker labels: identify who spoke in each segment.
  • Word-level timing (optional): fine-grained alignment when you need it.

In this guide, you’ll:

  1. Call Deepgram with utterances, diarize, and smart_format enabled.
  2. Understand the response (words → utterances → speakers).
  3. Normalize it into a “turns” data model you can store, index, and analyze.

Speech Is Made of Contextual Segments—Text Should Be Too!

Human speech isn’t a neat paragraph; it comes in segments like questions, answers, interjections, and hand-offs. To keep that structure, your transcript needs three things:

  • Utterances: coherent segments of speech with a single intent.
  • Timestamps: start/end times for each segment (and words) so you can align UI, video, or actions.

How Deepgram exposes this (out of the box):

  • Enable utterances=true to receive results.utterances[] with {start, end, transcript, confidence, words[]}.
  • Enable diarize=true to add speaker labels per utterance (and per word).
  • Enable smart_format=true for readable punctuation/casing and normalized entities (numbers, dates, etc.).

Working with Utterances, Timestamps, and Diarization in Deepgram

With Nova-2 and Nova-3, Deepgram can return timestamped transcripts complete with utterances and speaker diarization STT—all in one call. To enable these features, all you need to do is pass the corresponding parameters in your API request.

Example Curl Command:

curl \
  -X POST \
  -H "Authorization: Token YOUR_DEEPGRAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav"}' \
  "https://api.deepgram.com/v1/listen?model=nova-3&language=en&utterances=true&diarize=true&smart_format=true"

Example JSON Response:

{
  "start": 10.0713,
  "end": 11.6713,
  "confidence": 0.9994,
  "channel": 0,
  "transcript": "Life moves pretty fast.",
  "words": [
    {"word":"Life","start":10.0713,"end":10.3113,"confidence":0.9990,"speaker":0},
    {"word":"moves","start":10.3113,"end":10.6313,"confidence":0.9997,"speaker":0}
  ],
  "speaker": 0,
  "id": "35404fd9-12ed-4b58-a9a9-9eaf93475ef6"
}

Python SDK (prerecorded)

from deepgram import DeepgramClient, PrerecordedOptions

dg = DeepgramClient("YOUR_SECRET")

AUDIO_URL = {"url": "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav"}

opts = PrerecordedOptions(
    model="nova-3",
    language="en",
    smart_format=True,
    utterances=True,
    diarize=True,
)

res = dg.listen.prerecorded.v("1").transcribe_url(AUDIO_URL, opts)

print(res.to_json(indent=2))

Adding Captions to Audio with Deepgram

Deepgram’s timestamped transcripts (with utterances=true and optional diarize=true) map cleanly to standard caption formats: SRT and WebVTT.

Format Time syntax Speaker tags Best for
SRT HH:MM:SS,mmm Not standard Offline editors, legacy players
WebVTT HH:MM:SS.mmm native HTML5 & styling via ::cue

Option A: Use the Caption Helpers

from deepgram import DeepgramClient, PrerecordedOptions
from deepgram_captions import DeepgramConverter, webvtt, srt

dg = DeepgramClient()  # reads DEEPGRAM_API_KEY from env
with open("PATH_TO_YOUR_FILE", "rb") as f:
    payload = f.read()

opts = PrerecordedOptions(
    model="nova-3",
    language="en",
    smart_format=True,
    utterances=True,
    diarize=True,
)

res = dg.listen.rest.v("1").transcribe_file(payload, opts)
dg_tx = DeepgramConverter(res.to_dict())  # convert SDK object to plain dict

# Write WebVTT
with open("output.vtt", "w", encoding="utf-8") as out:
    out.write(webvtt(dg_tx))

# Write SRT
with open("output.srt", "w", encoding="utf-8") as out:
    out.write(srt(dg_tx))

Production Pointers

  • Line length and duration: keep cues ≤ 42 chars and ≤ 6 s. Split long utterances if needed.
  • Overlap: if back-channels overlap, shift them ±100 ms or merge.
  • Async transcription: use transcribe_file_async + webhook for large batches.

Conclusion: Transcription Is Just the Beginning

Treating speech as structured data—not just words—unlocks real product value. With Deepgram, you get timestamped transcripts, utterances, and speaker diarization, enabling you to answer who said what, and when.