Skip to main content

Overview

Omi’s transcription system provides real-time speech-to-text conversion with speaker identification, multiple language support, and seamless integration with the conversation processing pipeline.
Connect to /v4/listen WebSocket with your user token and start streaming audio. Transcripts arrive in real-time as JSON.

WebSocket Endpoint

WebSocket connections require Firebase authentication. The uid parameter must be a valid user ID obtained through Firebase Auth.

Endpoint URL

Query Parameters

Type: stringUser ID obtained from Firebase authentication. Required for all connections.
Type: string | Default: 'en'Language code for transcription. Supports:
  • Standard codes: 'en', 'es', 'fr', 'de', 'ja', 'zh', etc.
  • Multi-language: 'multi' for automatic language detection
Type: integer | Default: 8000Audio sample rate in Hz. Common values: 8000, 16000, 44100, 48000
Type: string | Default: 'pcm8'Audio codec. Supported options:
  • pcm8 - 8-bit PCM (default)
  • pcm16 - 16-bit PCM
  • opus - Opus codec (16kHz)
  • opus_fs320 - Opus with 320 frame size
  • aac - AAC codec
  • lc3 - LC3 codec
  • lc3_fs1030 - LC3 with 1030 frame size
Type: integer | Default: 1Number of audio channels. Use 1 for mono, 2 for stereo.
Type: boolean | Default: trueEnable speaker identification using the user’s stored speech profile. When enabled, the system extracts a speaker embedding from the user’s speech profile and uses it to identify the user’s voice via biometric matching.
Type: integer | Default: 120 | Range: 2-14400Seconds of silence before the conversation is automatically processed. After this timeout, the conversation is saved and LLM processing begins.
Type: string | OptionalExplicitly specify STT service. Options: deepgram. If not specified, Deepgram is used.
Type: string | Default: 'disabled'Enable custom STT mode. When set to 'enabled', the backend accepts app-provided transcripts instead of using STT services. Useful for apps with their own transcription.
Type: string | OptionalConversation source identifier. Examples: 'omi', 'openglass', 'phone'

Audio Codecs

The system supports multiple audio codecs with automatic decoding:
All audio is internally converted to 16-bit linear PCM before being sent to STT providers.

STT Service Selection

The selected streaming provider comes from the ordered STT_SERVICE_MODELS configuration. The first configured model that supports the requested language wins. Pre-recorded voice and sync routes use the corresponding STT_PRERECORDED_MODEL selection contract.

Provider Capabilities

Transcription outcome contract

Transport success is not transcription success. The backend uses one bounded semantic vocabulary across voice upload, voice-message SSE, offline sync, and live provider failures: POST /v2/voice-message/transcribe returns outcome alongside transcript, stt_provider, and stt_model. True silence remains HTTP 200 with an empty transcript and outcome=expected_silence. All failure outcomes use a non-2xx status and a fixed response body containing only error, outcome, provider, retryable, and a public-safe message; provider response bodies, audio identifiers, and exception text are never exposed. The /v2/voice-messages stream emits the same safe failure object in a terminal error: SSE frame. A normal empty stream is reserved for explicit expected_silence. For /v4/listen, an unusable initial or mid-session STT socket emits this event before the client connection closes with WebSocket code 1011:
The backend retains any buffered audio it could not hand to the provider. It does not keep a green client WebSocket while discarding later audio; the close activates the client’s existing reconnect or local-recovery path.

Production transcription candidate gate

The manual backend workflow deploys a no-traffic, uniquely tagged backend candidate and proves the real /v2/voice-message/transcribe route before shifting any Cloud Run traffic. The same path runs for an explicit development deployment first, which is the required identity-and-route dry run before a production release. The tag resolver requires the exact candidate revision recorded in Cloud Run status.traffic; it cannot accidentally exercise the current serving revision or latest-created revision. backend/testing/release_fixtures/transcription-release-probe.wav and its versioned JSON manifest provide the known audio, language, expected transcript, SHA-256 digest, and CC-BY-4.0 LibriSpeech provenance. The gate requires HTTP 200, outcome=success, and the exact normalized transcript. It intentionally does not assert provider or model identity: this is a semantic capability gate, not an unreviewed routing-policy setting. The shared transcription-release-candidate-probe action uses the existing authenticated deploy identity to read the existing FIREBASE_API_KEY Secret Manager secret, sign a five-minute Firebase custom token for the dedicated non-human omi-release-probe UID, and exchange it immediately for an ID token. It writes that token only to an owner-only temporary runner file, never exposes it through workflow outputs or evidence, and deletes it at step exit. The workflow makes no IAM changes: the existing deploy identity must be reviewed to have only the Secret Manager read and iam.serviceAccounts.signJwt access this action needs. Missing access fails closed before promotion. Reports contain only redacted booleans and status codes. The Cloud Run candidate itself makes the private VPC hop to Parakeet. After a passing or failed candidate gate, the workflow removes its temporary tag; a failed gate never shifts traffic.

Automatic development candidate acceptance

gcp_backend_auto_dev.yml keeps the development backend mutation lock while it deploys the four Cloud Run services (backend, backend-sync, backend-sync-backfill, and backend-integration) with the service-scoped candidate tag. It resolves each exact tag URL from Cloud Run status, runs the source-owned backend/deploy/dev_candidate_acceptance.json manifest, and only then permits the one traffic-promotion step. The backend uses the authenticated What Matters Now contract; the worker services use bounded /v1/health checks. The evidence artifact records only service, bounded contract category, and outcome — never URLs, tokens, user data, or response bodies. Candidate requests carry an OIDC token in X-Serverless-Authorization while the application keeps its own Authorization header. The token audience is the canonical Cloud Run service URL as required by Cloud Run; the HTTP target remains the exact no-traffic tagged candidate URL. Development pusher is deliberately GKE-only (pusher.omiapi.com). A legacy Cloud Run pusher service is not a deploy, candidate, or health-report surface; do not publish an image merely to make that retired surface appear ready. During the direct-URL retirement window, the public dev Cloud Run backend and legacy backend-listen services must use http://pusher.omiapi.com. Other dev Cloud Run services and jobs must not define HOSTED_PUSHER_API_URL. Retire those public endpoints only after they show no /v4/listen traffic.

Deepgram Configuration

When using Deepgram, the following options are configured:

External Custom STT Service

Build your own transcription/diarization WebSocket service that integrates with Omi.

Your Service Receives

Your Service Sends

Format: JSON object with segments array

Segment Fields

Requirements

  • Response must be an object with segments key. Raw arrays [{...}] will fail.
  • Do not include a type field, or set it to "Results". Other values are ignored.
  • Connection closes after 90 seconds of inactivity.

Speech Profile & Speaker Embedding

When a user has a speech profile, the system uses speaker embedding comparison to identify the user’s voice in real-time.

How It Works

Speech Profile Benefits

  1. User Identification: Speaker embedding comparison identifies the device owner by voice biometrics
  2. No Startup Delay: Transcription begins immediately (no profile audio prepending)
  3. Single Socket: One Deepgram connection per session (reduced API costs)

Transcription Flow

Connection Established

WebSocket connection accepted, user validated, STT provider selected based on language.

Audio Streaming

App sends binary audio chunks. Backend decodes based on codec parameter.

STT Processing

Decoded audio sent to Deepgram. Provider returns word-level transcripts with speaker IDs.

Segment Creation

Words grouped into segments. Same-speaker consecutive words merged. Timing adjusted for speech profile offset.

Real-time Delivery

JSON segments streamed back to app immediately. UI updates as user speaks.

Conversation Lifecycle

Background task monitors silence. After conversation_timeout, conversation is processed and saved.

Message Formats

Incoming Messages (App → Backend)

Format: BinaryRaw audio bytes encoded according to the codec parameter. Sent continuously during recording.
Keep-alive: Messages of 2 bytes or less are treated as heartbeat pings.

Outgoing Messages (Backend → App)

Format: JSON ArrayReal-time transcript segments as they’re detected:

Transcript Segment Model

Each transcript segment contains:

Connection Lifecycle

Lifecycle Events

Open

  1. WebSocket accepted
  2. User authentication verified
  3. Language/STT service selected
  4. STT connections initialized (with retry logic)
  5. Speech profile loaded in background
  6. Heartbeat task started (10s interval)

Stream

  1. Audio received and decoded
  2. Sent to STT provider(s)
  3. Results collected in buffers
  4. Processed every 600ms
  5. Segments sent to client
  6. Speaker suggestions generated

Close

  1. Usage statistics recorded
  2. All STT sockets closed
  3. Client WebSocket closed (code 1000/1001)
  4. Buffers and collections cleared

Error Handling & Retry Logic

The system includes robust error handling:
Live STT never silently downgrades a terminal provider failure to a successful transcription. The app receives the bounded failure status before the 1011 close and must retain unconfirmed local audio until a later successful sync.

Key File Locations

Backend Deep Dive

Complete backend architecture overview

Storing Conversations

How conversations and memories are stored

Chat System

How the AI chat system uses transcriptions

Backend Setup

Environment setup and configuration