# Groq vs OpenAI Whisper Backends: Key Differences in claude-video

> Discover the core distinctions and shared logic between Groq and OpenAI Whisper backends in claude-video. Understand endpoint URLs, models, API keys and more.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: deep-dive
- Published: 2026-07-19

---

**Groq and OpenAI Whisper backends differ only in endpoint URLs, model identifiers, API key environment variables, and User-Agent headers, while sharing identical chunking, retry, and parsing logic.**

The **claude-video** repository provides a flexible transcription system that supports both Groq's Whisper-compatible API and OpenAI's native Whisper API through a unified implementation. While both backends process audio identically after upload, they require distinct configuration values and API credentials to route requests correctly.

## Configuration and Endpoint Differences

The transcription backend selection is controlled through environment variables and hardcoded endpoint definitions in the whisper processing module.

### Endpoint URLs and Model Names

In [`skills/watch/scripts/whisper.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/whisper.py) (lines 29-34), the endpoints are defined as constants:

- **Groq**: `https://api.groq.com/openai/v1/audio/transcriptions` with model `whisper-large-v3`
- **OpenAI**: `https://api.openai.com/v1/audio/transcriptions` with model `whisper-1`

Groq hosts the largest available Whisper model (`whisper-large-v3`), while OpenAI defaults to `whisper-1`. The code selects the appropriate URL and model pair based on which API key is detected.

### API Key Preference Logic

The `load_api_key` function (lines 65-71 and 98-108) implements a priority-based selection system:

1. Check for `GROQ_API_KEY` first
2. Fall back to `OPENAI_API_KEY` if Groq key is absent

This means **Groq is the preferred backend** when both keys are present in the environment. The same selection logic applies regardless of which service you intend to use, making the skill automatically "Groq-first" but OpenAI-compatible.

## Technical Implementation Details

Despite different endpoints, the client-side implementation remains unified across both services.

### User-Agent Header Requirements

Groq's Cloudflare edge protection blocks generic Python User-Agent strings, requiring a custom header. The `_post_whisper` function (lines 45-51) sets:

```python
headers = {
    "User-Agent": "watch-skill/1.0 (+claude-code; python-urllib)",
    "Authorization": f"Bearer {api_key}"
}

```

This custom User-Agent is sent to both backends, though it only matters for Groq's Cloudflare configuration. OpenAI accepts the header without requiring it.

### Shared Processing Pipeline

Both backends follow identical workflows after the initial request:

- **Audio extraction**: `extract_audio()` converts video to mono 16kHz MP3
- **Chunk planning**: `plan_chunks()` splits files exceeding `MAX_UPLOAD_BYTES` (25 MiB)
- **Multipart upload**: `_build_multipart()` constructs requests without external HTTP libraries
- **Rate limit handling**: `_post_whisper` counts HTTP 429 responses and retries up to `MAX_429_RETRIES` (lines 71-78)
- **Response parsing**: `_segments_from_response()` normalizes JSON segments into unified `{start, end, text}` objects

The only backend-specific code paths are the endpoint URL construction, model name parameter, and the API key selection logic.

## How to Configure Each Backend

You can control which backend activates through environment variables or CLI arguments.

### Using Groq (Default)

Set the Groq API key as the preferred credential:

```bash

# ~/.config/watch/.env

GROQ_API_KEY="your-groq-key-here"

```

Or via environment variable:

```bash
export GROQ_API_KEY="gsk_..."
python3 -m skills.watch.scripts.whisper /path/to/video.mp4

```

### Using OpenAI

Force OpenAI backend selection via CLI flag:

```bash
watch https://youtu.be/xyz --whisper openai

```

Or ensure only `OPENAI_API_KEY` is set while `GROQ_API_KEY` is absent:

```bash
export OPENAI_API_KEY="sk-..."
watch https://youtu.be/xyz

```

## Summary

- **Groq and OpenAI Whisper backends** share the same chunking, retry, and response parsing logic in [`skills/watch/scripts/whisper.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/whisper.py)
- **Endpoint differences**: Groq uses `api.groq.com` with model `whisper-large-v3`; OpenAI uses `api.openai.com` with model `whisper-1`
- **API key hierarchy**: `GROQ_API_KEY` takes precedence over `OPENAI_API_KEY` when both exist
- **User-Agent requirement**: Groq requires a custom User-Agent header to bypass Cloudflare blocks, while OpenAI works with or without it
- **Transparent switching**: The skill automatically selects backends based on available credentials, requiring no code changes to switch providers

## Frequently Asked Questions

### Which backend is faster, Groq or OpenAI?

According to the claude-video source code, both services implement identical client-side retry logic with `MAX_429_RETRIES`, but Groq typically offers faster inference speeds due to optimized hardware acceleration for the `whisper-large-v3` model. However, the repository treats both as functionally equivalent in terms of API reliability and response format.

### Can I use both Groq and OpenAI in the same project?

Yes. The skill's `load_api_key` function checks for `GROQ_API_KEY` first and falls back to `OPENAI_API_KEY` only if the Groq key is missing. To force OpenAI when both keys exist, use the `--whisper openai` CLI flag when invoking the watch command, or temporarily unset `GROQ_API_KEY` in your environment.

### Why does the Groq backend need a custom User-Agent?

Groq's API endpoint sits behind Cloudflare's edge protection, which blocks requests from generic Python User-Agent strings by default. The custom `watch-skill/1.0 (+claude-code; python-urllib)` header defined in `_post_whisper` (lines 45-51) identifies the request as coming from the claude-video skill rather than an unconfigured script, preventing 403 errors while maintaining security.

### What happens if my audio file exceeds 25 MiB?

Both backends handle large files identically. The `plan_chunks()` function splits the audio into time-aligned segments under `MAX_UPLOAD_BYTES`, then `_build_multipart()` uploads each chunk separately. The `_segments_from_response()` function reassembles the timestamps into a continuous transcript regardless of which provider processed the audio.