Deepgram Production Checklist
Overview
Comprehensive go-live checklist for Deepgram integrations. Covers singleton client, health checks, Prometheus metrics, alert rules, error handling, and a phased go-live timeline.
Production Readiness Matrix
| Category |
Item |
Status |
| Auth |
Production API key with scoped permissions |
[ ] |
| Auth |
Key stored in secret manager (not env file) |
[ ] |
| Auth |
Key rotation schedule (90-day) configured |
[ ] |
| Auth |
Fallback key provisioned and tested |
[ ] |
| Resilience |
Retry with exponential backoff on 429/5xx |
[ ] |
| Resilience |
Circuit breaker for cascade failure prevention |
[ ] |
| Resilience |
Request timeout set (30s pre-recorded, 10s TTS) |
[ ] |
| Resilience |
Graceful degradation when API unavailable |
[ ] |
| Performance |
Singleton client (not creating per-request) |
[ ] |
| Performance |
Concurrency limited (50-80% of plan limit) |
[ ] |
| Performance |
Audio preprocessed (16kHz mono for best results) |
[ ] |
| Performance |
Large files use callback URL (async) |
[ ] |
| Monitoring |
Health check endpoint testing Deepgram API |
[ ] |
| Monitoring |
Prometheus metrics: latency, error rate, usage |
[ ] |
| Monitoring |
Alerts: error rate >5%, latency >10s, circuit open |
[ ] |
| Security |
PII redaction enabled if handling sensitive audio |
[ ] |
| Security |
Audio URLs validated (HTTPS, no private IPs) |
[ ] |
| Security |
Audit logging on all operations |
[ ] |
Instructions
Step 1: Production Singleton Client
import { createClient, DeepgramClient } from '@deepgram/sdk';
class ProductionDeepgram {
private static client: DeepgramClient | null = null;
static getClient(): DeepgramClient {
if (!this.client) {
const key = process.env.DEEPGRAM_API_KEY;
if (!key) throw new Error('DEEPGRAM_API_KEY required for production');
this.client = createClient(key);
}
return this.client;
}
// Force re-init (for key rotation)
static reset() { this.client = null; }
}
Step 2: Health Check Endpoint
import express from 'express';
import { createClient } from '@deepgram/sdk';
const app = express();
const deepgram = createClient(process.env.DEEPGRAM_API_KEY!);
app.get('/health', async (req, res) => {
const start = Date.now();
try {
// Test API connectivity by listing projects
const { error } = await deepgram.manage.getProjects();
const latency = Date.now() - start;
if (error) {
return res.status(503).json({
status: 'unhealthy',
deepgram: 'error',
error: error.message,
latency_ms: latency,
});
}
res.json({
status: 'healthy',
deepgram: 'connected',
latency_ms: latency,
timestamp: new Date().toISOString(),
});
} catch (err: any) {
res.status(503).json({
status: 'unhealthy',
deepgram: 'unreachable',
error: err.message,
latency_ms: Date.now() - start,
});
}
});
Step 3: Prometheus Metrics
import { Counter, Histogram, Gauge, Registry } from 'prom-client';
const registry = new Registry();
const transcriptionRequests = new Counter({
name: 'deepgram_requests_total',
help: 'Total Deepgram API requests',
labelNames: ['method', 'model', 'status'],
registers: [registry],
});
const transcriptionLatency = new Histogram({
name: 'deepgram_latency_seconds',
help: 'Deepgram API request latency',
labelNames: ['method', 'model'],
buckets: [0.5, 1, 2, 5, 10, 30],
registers: [registry],
});
const audioProcessed = new Counter({
name: 'deepgram_audio_seconds_total',
help: 'Total audio seconds processed',
labelNames: ['model'],
registers: [registry],
});
const activeConnections = new Gauge({
name: 'deepgram_active_connections',
help: 'Active WebSocket connections',
registers: [registry],
});
// Instrumented transcription
async function instrumentedTranscribe(url: string, model = 'nova-3') {
const timer = transcriptionLatency.startTimer({ method: 'prerecorded', model });
try {
const { result, error } = await deepgram.listen.prerecorded.transcribeUrl(
{ url }, { model, smart_format: true }
);
timer();
transcriptionRequests.inc({ method: 'prerecorded', model, status: error ? 'error' : 'ok' });
if (result?.metadata?.duration) {
audioProcessed.inc({ model }, result.metadata.duration);
}
if (error) throw error;
return result;
} catch (err) {
timer();
transcriptionRequests.inc({ method: 'prerecorded', model, status: 'error' });
throw err;
}
}
// Expose metrics endpoint
app.get('/metrics', async (req, res) => {
res.set('Content-Type', registry.contentType);
res.send(await registry.metrics());
});
Step 4: Alert Rules (Prometheus/AlertManager)
groups:
- name: deepgram
rules:
- alert: DeepgramHighErrorRate
expr: rate(deepgram_requests_total{status="error"}[5m]) / rate(deepgram_requests_total[5m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "Deepgram error rate > 5%"
- alert: DeepgramHighLatency
expr: histogram_quantile(0.95, rate(deepgram_latency_seconds_bucket[5m])) > 10
for: 5m
labels:
severity: warning
annotations:
summary: "Deepgram P95 latency > 10s"
- alert: DeepgramHealthCheckFailed
expr: up{job="deepgram-service"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Deepgram health check failed for 2+ minutes"
Step 5: Error Handling Wrapper
async function safeTranscribe(url: string, options: Record<string, any> = {}) {
const timeout = options.timeout ?? 30000;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const result = await Promise.race([
instrumentedTranscribe(url, options.model ?? 'nova-3'),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Transcription timeout')), timeout)
),
]);
clearTimeout(timeoutId);
return result;
} catch (err: any) {
clearTimeout(timeoutId);
// Log structured error
console.error(JSON.stringify({
level: 'error',
service: 'deepgram',
message: err.message,
url: url.substring(0, 100),
timestamp: new Date().toISOString(),
}));
throw err;
}
}
Step 6: Go-Live Timeline
| Phase |
When |
Actions |
| D-7 |
1 week before |
Load test at 2x expected volume, security review |
| D-3 |
3 days before |
Smoke test with production key, verify all alerts fire |
| D-1 |
Day before |
Confirm on-call rotation, validate dashboards |
| D-0 |
Launch |
Shadow mode (10% traffic), monitoring open |
| D+1 |
Day after |
Review error rate, latency, verify no anomalies |
| D+7 |
1 week after |
Full traffic, tune alert thresholds based on baselines |
Output
- Singleton client with reset capability
- Health check endpoint with latency reporting
- Prometheus metrics (requests, latency, audio, connections)
- AlertManager rules for error rate, latency, availability
- Timeout-safe transcription wrapper
- Phased go-live timeline
Error Handling
| Issue |
Cause |
Solution |
| Health check 503 |
API key expired |
Rotate key, check secret manager |
| Metrics not scraped |
Wrong port/path |
Verify Prometheus target config |
| Alert storms |
Thresholds too tight |
Add for: duration, tune values |
| Timeout on large files |
Sync mode too slow |
Switch to callback URL pattern |
Resources
1---2name: deepgram-prod-checklist3description: Execute Deepgram production deployment checklist. Use when preparing for production launch, auditing production readiness, or verifying deployment configurations. Trigger: "deepgram production", "deploy deepgram", "deepgram prod checklist", "deepgram go-live", "production ready deepgram".4license: MIT5---6# Deepgram Production Checklist78## Overview9Comprehensive go-live checklist for Deepgram integrations. Covers singleton client, health checks, Prometheus metrics, alert rules, error handling, and a phased go-live timeline.1011## Production Readiness Matrix1213| Category | Item | Status |14|----------|------|--------|15| **Auth** | Production API key with scoped permissions | [ ] |16| **Auth** | Key stored in secret manager (not env file) | [ ] |17| **Auth** | Key rotation schedule (90-day) configured | [ ] |18| **Auth** | Fallback key provisioned and tested | [ ] |19| **Resilience** | Retry with exponential backoff on 429/5xx | [ ] |20| **Resilience** | Circuit breaker for cascade failure prevention | [ ] |21| **Resilience** | Request timeout set (30s pre-recorded, 10s TTS) | [ ] |22| **Resilience** | Graceful degradation when API unavailable | [ ] |23| **Performance** | Singleton client (not creating per-request) | [ ] |24| **Performance** | Concurrency limited (50-80% of plan limit) | [ ] |25| **Performance** | Audio preprocessed (16kHz mono for best results) | [ ] |26| **Performance** | Large files use callback URL (async) | [ ] |27| **Monitoring** | Health check endpoint testing Deepgram API | [ ] |28| **Monitoring** | Prometheus metrics: latency, error rate, usage | [ ] |29| **Monitoring** | Alerts: error rate >5%, latency >10s, circuit open | [ ] |30| **Security** | PII redaction enabled if handling sensitive audio | [ ] |31| **Security** | Audio URLs validated (HTTPS, no private IPs) | [ ] |32| **Security** | Audit logging on all operations | [ ] |3334## Instructions3536### Step 1: Production Singleton Client3738```typescript39import { createClient, DeepgramClient } from '@deepgram/sdk';4041class ProductionDeepgram {42 private static client: DeepgramClient | null = null;4344 static getClient(): DeepgramClient {45 if (!this.client) {46 const key = process.env.DEEPGRAM_API_KEY;47 if (!key) throw new Error('DEEPGRAM_API_KEY required for production');48 this.client = createClient(key);49 }50 return this.client;51 }5253 // Force re-init (for key rotation)54 static reset() { this.client = null; }55}56```5758### Step 2: Health Check Endpoint5960```typescript61import express from 'express';62import { createClient } from '@deepgram/sdk';6364const app = express();65const deepgram = createClient(process.env.DEEPGRAM_API_KEY!);6667app.get('/health', async (req, res) => {68 const start = Date.now();69 try {70 // Test API connectivity by listing projects71 const { error } = await deepgram.manage.getProjects();72 const latency = Date.now() - start;7374 if (error) {75 return res.status(503).json({76 status: 'unhealthy',77 deepgram: 'error',78 error: error.message,79 latency_ms: latency,80 });81 }8283 res.json({84 status: 'healthy',85 deepgram: 'connected',86 latency_ms: latency,87 timestamp: new Date().toISOString(),88 });89 } catch (err: any) {90 res.status(503).json({91 status: 'unhealthy',92 deepgram: 'unreachable',93 error: err.message,94 latency_ms: Date.now() - start,95 });96 }97});98```99100### Step 3: Prometheus Metrics101102```typescript103import { Counter, Histogram, Gauge, Registry } from 'prom-client';104105const registry = new Registry();106107const transcriptionRequests = new Counter({108 name: 'deepgram_requests_total',109 help: 'Total Deepgram API requests',110 labelNames: ['method', 'model', 'status'],111 registers: [registry],112});113114const transcriptionLatency = new Histogram({115 name: 'deepgram_latency_seconds',116 help: 'Deepgram API request latency',117 labelNames: ['method', 'model'],118 buckets: [0.5, 1, 2, 5, 10, 30],119 registers: [registry],120});121122const audioProcessed = new Counter({123 name: 'deepgram_audio_seconds_total',124 help: 'Total audio seconds processed',125 labelNames: ['model'],126 registers: [registry],127});128129const activeConnections = new Gauge({130 name: 'deepgram_active_connections',131 help: 'Active WebSocket connections',132 registers: [registry],133});134135// Instrumented transcription136async function instrumentedTranscribe(url: string, model = 'nova-3') {137 const timer = transcriptionLatency.startTimer({ method: 'prerecorded', model });138 try {139 const { result, error } = await deepgram.listen.prerecorded.transcribeUrl(140 { url }, { model, smart_format: true }141 );142 timer();143 transcriptionRequests.inc({ method: 'prerecorded', model, status: error ? 'error' : 'ok' });144 if (result?.metadata?.duration) {145 audioProcessed.inc({ model }, result.metadata.duration);146 }147 if (error) throw error;148 return result;149 } catch (err) {150 timer();151 transcriptionRequests.inc({ method: 'prerecorded', model, status: 'error' });152 throw err;153 }154}155156// Expose metrics endpoint157app.get('/metrics', async (req, res) => {158 res.set('Content-Type', registry.contentType);159 res.send(await registry.metrics());160});161```162163### Step 4: Alert Rules (Prometheus/AlertManager)164165```yaml166groups:167 - name: deepgram168 rules:169 - alert: DeepgramHighErrorRate170 expr: rate(deepgram_requests_total{status="error"}[5m]) / rate(deepgram_requests_total[5m]) > 0.05171 for: 5m172 labels:173 severity: critical174 annotations:175 summary: "Deepgram error rate > 5%"176177 - alert: DeepgramHighLatency178 expr: histogram_quantile(0.95, rate(deepgram_latency_seconds_bucket[5m])) > 10179 for: 5m180 labels:181 severity: warning182 annotations:183 summary: "Deepgram P95 latency > 10s"184185 - alert: DeepgramHealthCheckFailed186 expr: up{job="deepgram-service"} == 0187 for: 2m188 labels:189 severity: critical190 annotations:191 summary: "Deepgram health check failed for 2+ minutes"192```193194### Step 5: Error Handling Wrapper195196```typescript197async function safeTranscribe(url: string, options: Record<string, any> = {}) {198 const timeout = options.timeout ?? 30000;199200 const controller = new AbortController();201 const timeoutId = setTimeout(() => controller.abort(), timeout);202203 try {204 const result = await Promise.race([205 instrumentedTranscribe(url, options.model ?? 'nova-3'),206 new Promise((_, reject) =>207 setTimeout(() => reject(new Error('Transcription timeout')), timeout)208 ),209 ]);210 clearTimeout(timeoutId);211 return result;212 } catch (err: any) {213 clearTimeout(timeoutId);214 // Log structured error215 console.error(JSON.stringify({216 level: 'error',217 service: 'deepgram',218 message: err.message,219 url: url.substring(0, 100),220 timestamp: new Date().toISOString(),221 }));222 throw err;223 }224}225```226227### Step 6: Go-Live Timeline228229| Phase | When | Actions |230|-------|------|---------|231| D-7 | 1 week before | Load test at 2x expected volume, security review |232| D-3 | 3 days before | Smoke test with production key, verify all alerts fire |233| D-1 | Day before | Confirm on-call rotation, validate dashboards |234| D-0 | Launch | Shadow mode (10% traffic), monitoring open |235| D+1 | Day after | Review error rate, latency, verify no anomalies |236| D+7 | 1 week after | Full traffic, tune alert thresholds based on baselines |237238## Output239- Singleton client with reset capability240- Health check endpoint with latency reporting241- Prometheus metrics (requests, latency, audio, connections)242- AlertManager rules for error rate, latency, availability243- Timeout-safe transcription wrapper244- Phased go-live timeline245246## Error Handling247| Issue | Cause | Solution |248|-------|-------|----------|249| Health check 503 | API key expired | Rotate key, check secret manager |250| Metrics not scraped | Wrong port/path | Verify Prometheus target config |251| Alert storms | Thresholds too tight | Add `for:` duration, tune values |252| Timeout on large files | Sync mode too slow | Switch to `callback` URL pattern |253254## Resources255- [Deepgram Production Guide](https://developers.deepgram.com/docs/production-guide)256- [Prometheus Best Practices](https://prometheus.io/docs/practices/)257- [Deepgram SLA](https://deepgram.com/sla)258