Skip to main content
RapidDev - Software Development Agency
App Featuresmedia-content20 min read

How to Add Audio to Text Conversion to Your App (Copy-Paste Prompts Included)

Audio-to-text conversion needs a microphone input layer (MediaRecorder API), a transcription engine (OpenAI Whisper API at $0.006/minute or Deepgram Nova-2 at $0.0043/minute for streaming), a Supabase Edge Function to proxy the API call, and a transcript display with inline editing. With Lovable or V0 you can ship both a record tab and a file upload tab in 4–8 hours. Running costs start near zero and scale linearly with audio minutes — 100 users transcribing 10 minutes/month each costs roughly $6–15/mo.

4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members

Feature spec

Intermediate

Category

media-content

Build with AI

4–8 hours with Lovable or V0

Custom build

1–2 weeks custom dev

Running cost

$0–15/mo at 100 users; $150–600/mo at 10K users (transcription API dominates)

Works on

Web

Everything it takes to ship Audio to Text Conversion — parts, prompts, and real costs.

TL;DR

Audio-to-text conversion needs a microphone input layer (MediaRecorder API), a transcription engine (OpenAI Whisper API at $0.006/minute or Deepgram Nova-2 at $0.0043/minute for streaming), a Supabase Edge Function to proxy the API call, and a transcript display with inline editing. With Lovable or V0 you can ship both a record tab and a file upload tab in 4–8 hours. Running costs start near zero and scale linearly with audio minutes — 100 users transcribing 10 minutes/month each costs roughly $6–15/mo.

What Audio-to-Text Conversion Actually Is

Audio-to-text conversion turns spoken audio into editable, searchable text. There are two modes: live microphone transcription where words appear on screen as the user speaks, and batch file transcription where the user uploads an MP3 or WAV and gets a full transcript back in seconds. The transcription engine is the most important decision — Web Speech API is free but Chrome-only and English-heavy; OpenAI Whisper handles 99 languages and files up to 25 MB at $0.006/minute; Deepgram Nova-2 adds real-time streaming and speaker diarization at similar cost. The real product complexity is what happens after transcription: speaker labels, editable text, transcript history, and export formats.

What users consider table stakes in 2026

  • Live waveform visualizer during recording so users know the microphone is active — silence looks like a broken app
  • Real-time word display during microphone recording, not just a spinner until the whole recording is processed
  • File upload via drag-and-drop accepting MP3, M4A, WAV, WebM, and OGG — users come from voice memo apps and Zoom recordings
  • Speaker labels (Speaker A, Speaker B) for meeting transcription use cases — this is the most-requested feature after basic transcription
  • Inline transcript editing before saving — AI transcription makes mistakes and users need to correct them
  • Export as plain text or .docx without requiring another tool
  • Support for at minimum English, Spanish, and French from launch

Anatomy of the Feature

Six components. Three are UI, one is a cloud API service, one is a Supabase Edge Function proxy, and one is the storage and history layer. The Edge Function is the critical piece — calling Whisper from the browser directly triggers CORS errors and exposes your API key.

Layers:UIDataBackendService

Microphone input layer

UI

MediaDevices.getUserMedia({ audio: true }) requests microphone access. MediaRecorder captures audio chunks as audio/webm (Opus codec). On stop, the Blob is assembled from chunks and sent to the transcription Edge Function. A Web Audio API AnalyserNode drives the waveform visualizer by reading frequency data on each animation frame.

Note: getUserMedia only works on HTTPS and on published URLs — not inside Lovable's preview iframe or V0's sandbox. Test microphone recording on the deployed app exclusively.

Transcription engine

Service

OpenAI Whisper API (model: whisper-1) processes audio files up to 25 MB in 99 languages. Send with response_format: verbose_json to receive word-level timestamps alongside the transcript text. Deepgram Nova-2 is the production-grade alternative: $0.0043/minute for streaming real-time transcription with speaker diarization via a WebSocket connection.

Note: Do not call Whisper directly from browser JavaScript — it triggers CORS errors and exposes the API key in the client bundle. Always proxy through a Supabase Edge Function or Next.js API route.

Audio file upload

UI

react-dropzone (^14.x) handles drag-and-drop with audio/* MIME type filtering. Client-side validation checks file size before upload (Whisper max: 25 MB). The file is uploaded to Supabase Storage under the user's folder, then the storage URL is passed to the Edge Function rather than sending the raw file — avoids doubled upload time for large files.

Note: Whisper accepts MP3, MP4, MPEG, MPGA, M4A, WAV, WebM, and OGG. Display accepted formats explicitly in the dropzone label — 'Zoom recordings (.m4a), voice memos (.m4a, .mp3), or meeting exports (.wav, .webm)' converts better than a generic MIME string.

Transcript display

UI

Transcript text rendered in an editable textarea with paragraph breaks preserved. Speaker labels from diarization displayed as colored chips above each speaker's paragraph. Confidence-based word opacity: if Whisper verbose_json includes word-level confidence (approximated from segment avg_logprob), lower-confidence words render at slightly reduced opacity to flag them for review.

Note: Word-level timestamps from Whisper verbose_json enable click-to-seek: clicking a word in the transcript seeks the audio player to that timestamp. This is a 30-minute add-on after the basic transcript works.

Supabase Edge Function proxy

Backend

A Deno-based Supabase Edge Function receives the audio Blob or storage URL, authenticates the caller via the Supabase JWT, calls the Whisper API with the OPENAI_API_KEY from Deno.env.get(), and returns the verbose_json response. For file transcription, the function fetches the file from Supabase Storage using the service role key.

Note: Store OPENAI_API_KEY in Supabase Secrets (Cloud tab → Secrets), not in source code. For Deepgram real-time, a persistent WebSocket backend is harder to do on serverless Edge Functions — consider a small dedicated server for that use case.

Storage and history layer

Data

Supabase table transcriptions stores user_id, audio_url, transcript_text, transcript_json (the full verbose_json), language, duration_seconds, speaker_count, and status. RLS ensures users only see their own transcripts. A history page lists past transcriptions with title, date, duration, and a link to re-open and edit.

Note: The transcript_json column holds the raw Whisper response (typically 10–200 KB per transcript). Use jsonb, not json, so Postgres can index and query inside the document if needed.

The data model

One table with a status lifecycle covers the transcription pipeline. Run this in the Supabase SQL editor.

schema.sql
1create table public.transcriptions (
2 id uuid primary key default gen_random_uuid(),
3 user_id uuid references auth.users(id) on delete cascade not null,
4 title text,
5 audio_url text,
6 transcript_text text,
7 transcript_json jsonb,
8 language text not null default 'en',
9 duration_seconds int,
10 speaker_count int,
11 status text not null default 'pending'
12 check (status in ('pending', 'processing', 'done', 'error')),
13 created_at timestamptz not null default now()
14);
15
16alter table public.transcriptions enable row level security;
17
18create policy "Users can view own transcriptions"
19 on public.transcriptions for select
20 using (auth.uid() = user_id);
21
22create policy "Users can insert own transcriptions"
23 on public.transcriptions for insert
24 with check (auth.uid() = user_id);
25
26create policy "Users can update own transcriptions"
27 on public.transcriptions for update
28 using (auth.uid() = user_id);
29
30create policy "Users can delete own transcriptions"
31 on public.transcriptions for delete
32 using (auth.uid() = user_id);
33
34create index transcriptions_user_recent_idx
35 on public.transcriptions (user_id, created_at desc);

Heads up: Set status to 'processing' immediately on upload, then update to 'done' or 'error' when the Edge Function returns. This lets you show a loading state in the history list for in-progress transcriptions without polling the Edge Function.

Build it — pick your path

Each tool fits this feature differently. Switch tabs to compare fit, time, the exact steps, and a copy-paste prompt.

Hand-built by developersFit for this feature:

Custom build unlocks Deepgram WebSocket streaming for true real-time transcription, multi-speaker diarization with named voice profiles, and HIPAA-compliant audio pipelines for medical or legal use cases.

Step by step

  1. 1Implement Deepgram Nova-2 via WebSocket: open a wss://api.deepgram.com/v1/listen connection with diarize: true and smart_format: true parameters; pipe MediaRecorder audio chunks directly into the socket; receive interim and final transcripts as JSON events
  2. 2Build a speaker diarization display that color-codes transcript segments by speaker number and lets users rename 'Speaker 0' to 'John' for the full document
  3. 3Implement audio chunking for recordings longer than 25 minutes: split at natural silence points using Web Audio API silence detection, transcribe each chunk, concatenate results adjusting word timestamps by chunk offset
  4. 4Add a filler word removal post-processing step that strips 'um', 'uh', 'you know' from the final transcript text before saving

Where this path bites

  • Deepgram WebSocket streaming requires a persistent backend connection — not suitable for serverless Edge Functions; a small always-on server or Cloudflare Durable Object is needed
  • HIPAA compliance requires Business Associate Agreements with both the transcription API provider and your hosting/storage provider — verify BAA availability before committing to a provider

Third-party services you'll need

The transcription engine is the only paid dependency. Storage and the proxy layer run on Supabase:

ServiceWhat it doesFree tierPaid from
OpenAI Whisper APIBatch audio transcription — files up to 25 MB in 99 languages; returns transcript text and optional word-level timestamps in verbose_jsonNo free tier (pay per minute from first request)$0.006 per minute of audio transcribed (approx)
Deepgram Nova-2Production-grade real-time streaming transcription with speaker diarization; lower per-minute cost than Whisper at scale$200 free credit on sign-up$0.0043/minute streaming, $0.0036/minute batch (approx)
Supabase StorageStores uploaded audio files before sending to transcription API; also stores output audio for history playback1 GB storage, 2 GB bandwidth$25/mo (Pro) includes 100 GB storage + 200 GB bandwidth (approx)
Web Speech APIBrowser-native real-time transcription — no API key, no cost. Use as a live preview layer only on supported browsersFully free, browser built-inFree (Chrome/Edge only; not available on iOS Safari)

Swipe the table sideways to see pricing.

What it costs to run

Drag through the tiers to see how your monthly bill scales with users — no surprises later.

Estimated monthly running cost

$10/mo

Whisper at 10 minutes per user per month: 100 × 10 × $0.006 = $6. Supabase free tier covers storage and database. Total roughly $6–15/mo depending on actual usage.

Estimates use verified 2026 pricing and assume typical usage per user. Your real bill depends on activity, storage, and third-party plans.

What breaks when AI tools build this

The failures people actually hit on their first build — the symptom, why it happens, and the exact fix.

Microphone blocked in Lovable preview and V0 sandbox

Symptom: getUserMedia() throws NotAllowedError inside sandboxed iframes — which is exactly what Lovable's preview pane and V0's sandbox environment use. The microphone permission dialog never appears; the browser silently blocks the call. This leads builders to think their code is broken when the deployed version works fine.

Fix: Test all microphone functionality exclusively on the published HTTPS URL. In Lovable, click Publish and open the published link on your phone or desktop browser. Add a UI banner in the Record tab during development: 'Microphone testing requires the published app — preview mode does not support camera or microphone access.' This sets the right expectation and prevents wasted debugging time.

Whisper API rejects files over 25 MB with a 413 error

Symptom: OpenAI Whisper has a hard 25 MB file size limit. A 1-hour Zoom recording at typical quality is 60–120 MB. When a large file is sent to the API, it returns HTTP 413 Request Entity Too Large — but AI-generated code often doesn't handle this error, so the user sees a generic 'something went wrong' toast with no explanation of what to do.

Fix: Add client-side file size validation in react-dropzone's validator prop before the upload starts. Show a specific error: 'This file is 87 MB, which exceeds the 25 MB Whisper limit. Try compressing it first, or use a shorter recording.' For power users who regularly transcribe long recordings, add ffmpeg.wasm to split the audio into 3-minute chunks on the client, transcribe each chunk, and concatenate the results adjusting timestamps by the chunk offset.

CORS error when calling Whisper directly from the browser

Symptom: api.openai.com does not include the caller's origin in its CORS response headers when called from browser JavaScript. The browser blocks the request before it reaches OpenAI, and the browser console shows 'CORS policy: No Access-Control-Allow-Origin header'. Additionally, calling Whisper from the browser would require putting the API key in client-side code, where any user can read it from DevTools.

Fix: Always proxy Whisper calls through a Supabase Edge Function or Next.js API route on the server. The Edge Function reads OPENAI_API_KEY from Deno.env.get() (stored in Supabase Secrets) and never exposes it to the client. This pattern also lets you add per-user rate limiting and usage logging in the proxy.

Web Speech API code generated instead of Whisper

Symptom: When prompting Lovable or V0 for 'speech to text', they frequently generate SpeechRecognition (Web Speech API) code. Web Speech API is Chrome and Edge only — it does not work in Safari, Firefox, or iOS WebKit. Users on iPhones open the app and see nothing happen when they tap Record, because SpeechRecognition is not available in their browser.

Fix: Explicitly name OpenAI Whisper in your prompt: 'use OpenAI Whisper API via a Supabase Edge Function, not the browser SpeechRecognition API.' If you want live word display, use Web Speech API as a visual-only layer on supported browsers (firing on interim results) while still sending the final Blob to Whisper for the authoritative transcript — that gives real-time feel without sacrificing cross-browser compatibility.

Whisper verbose_json word timestamps drift in long recordings

Symptom: Whisper's verbose_json word-level timestamps are accurate for the first 5 minutes of audio. In longer recordings, timestamp drift accumulates — by minute 20, words can be off by 10–15 seconds. This makes click-to-seek features unreliable for meeting transcription of typical 45–60 minute calls.

Fix: For recordings over 5 minutes, split audio into 3-minute chunks before sending to Whisper. Transcribe each chunk independently and offset the returned timestamps by the cumulative chunk start time before concatenating. Store chunks as an array in transcript_json so you can reconstruct the original recording for playback if needed.

Best practices

1

Always proxy Whisper API calls through a server-side function — never call api.openai.com from browser JavaScript, both for CORS reasons and to keep your API key secret

2

Validate file size client-side before upload and show a specific, actionable error — 'exceeds 25 MB limit' is more helpful than a generic API error

3

Use response_format: verbose_json in Whisper requests to get word-level timestamps from the start — retrofitting click-to-seek later requires a data model change if you only stored plain text

4

Show a waveform visualizer during recording so users know the microphone is active — a blank recording UI looks identical to a broken one

5

Set transcription status to 'processing' immediately on submit and poll or use Supabase Realtime to update when done — users who navigate away and come back should see their transcript ready

6

Cache transcription results in the database by audio file hash — if two users upload the same Zoom recording, only call Whisper once

7

Display accepted file formats explicitly in the dropzone ('MP3, M4A, WAV, WebM, OGG up to 25 MB') — this single UI copy change reduces support requests about why uploads fail

When You Need Custom Development

Lovable and V0 comfortably cover batch file transcription and basic microphone recording. These use cases push past what AI tool scaffolding handles reliably:

  • Real-time speaker diarization with custom voice profiles — matching speakers across sessions by voice fingerprint requires Deepgram WebSocket streaming with a persistent backend, not a serverless Edge Function
  • HIPAA-compliant medical dictation pipeline — requires Business Associate Agreements with the transcription provider, end-to-end encryption at rest, and audit logs of every API call that touches PHI
  • Integration with a meeting platform (Zoom, Google Meet, Teams) via their recording or bot APIs to auto-transcribe meetings without any user upload step
  • Custom vocabulary boosting for legal or technical domains — medical terms, legal citations, product names — which Deepgram supports via keyword boosting but requires backend configuration beyond a simple API key swap

RapidDev builds these features for production

Real auth, database, and payments — fixed price, delivered in weeks. You own 100% of the code.

Get a fixed-price quote

Frequently asked questions

What's the cheapest way to add speech-to-text to a web app?

Web Speech API costs nothing — it's built into Chrome, Edge, and desktop Safari. The catch: it's English-heavy, not available on iOS Safari, and gives no transcript history or file upload. For a production app that needs cross-browser support and multi-language, OpenAI Whisper at $0.006/minute is the most cost-effective paid option. At 10 minutes of audio per user per month, 100 users costs roughly $6/mo in API fees — significantly less than most SaaS subscription tiers.

Can I transcribe audio in multiple languages with Whisper?

Yes. Whisper supports 99 languages and auto-detects the language by default. To specify a language explicitly — which improves accuracy and skips the detection step — add a language parameter to the API request with the ISO 639-1 code ('es' for Spanish, 'fr' for French, 'de' for German). For multi-language meeting recordings where speakers switch languages mid-conversation, let Whisper auto-detect; the model handles code-switching reasonably well.

How do I handle audio files larger than 25 MB for transcription?

Whisper enforces a hard 25 MB limit per request. For longer files, use ffmpeg.wasm in the browser to split the audio into 3-minute chunks before sending to your Edge Function. Each chunk goes to Whisper independently. Concatenate the results by offsetting the timestamps from each chunk by the cumulative start time of previous chunks. Store the chunk array in your transcript_json field so you can reconstruct the original timeline if needed.

What's the difference between Web Speech API and Whisper API?

Web Speech API runs in the browser, is free, and gives you words in real time as the user speaks — but only works in Chrome and Edge (not iOS Safari or Firefox), is trained primarily on English, and produces no permanent transcript you can retrieve later. Whisper runs on OpenAI's servers, costs $0.006/minute, works in 99 languages, accepts uploaded audio files, and returns a permanent transcript with optional word timestamps. Use Web Speech API as a real-time 'live preview' layer on supported browsers, and send the final audio Blob to Whisper for the authoritative, cross-browser-compatible result.

Can I show a live transcript while the user is still speaking?

For Chrome/Edge users: yes, use Web Speech API's onresult event which fires on interim and final results as speech is recognized. Words appear in real time. For iOS Safari and Firefox users: no native real-time option exists — the best you can do is show a waveform visualizer during recording and display the full Whisper transcript when they stop. A common pattern is to use Web Speech API for the live preview on supported browsers and always send the final audio to Whisper for the saved transcript, so the history is always Whisper-quality regardless of browser.

How do I add speaker labels to a transcription?

Whisper does not natively diarize speakers (it transcribes what was said, not who said it). For speaker labels, either use Deepgram Nova-2 with diarize: true in the request parameters — it returns speaker numbers with each word — or run pyannote-audio as a post-processing step on your server to add speaker segmentation to a Whisper transcript. Deepgram is the simpler option at $0.0043/minute; it adds speaker labels without changing your frontend at all, just the API response schema.

Is Whisper accurate enough for meeting transcription?

For English in a quiet environment, Whisper achieves roughly 5% word error rate — good enough for meeting notes where humans will review and correct. Accuracy drops in meetings with crosstalk, strong accents, or heavy technical jargon. For critical workflows (legal depositions, medical dictation), pair Whisper with post-processing to flag low-confidence segments using the avg_logprob values in verbose_json, and always build in an editing step before the transcript is finalized.

How do I export a transcript as a Word document?

Use the docx.js library (^8.x) to generate a .docx file client-side. Create a Document with a Paragraph for each transcript segment or speaker block, then call Packer.toBlob(doc) and trigger a download with URL.createObjectURL(). This runs entirely in the browser — no server required for export. For PDF export, jsPDF is the equivalent client-side library. Both add roughly 50 lines of code and no additional API cost.

RapidDev

Need this feature production-ready?

RapidDev builds audio to text conversion into real apps — auth, database, payments — at $13K–$25K.

Book a free consultation

30-min call. No commitment.

Want this built for you?

We ship production apps at a fixed price — $13K–$25K, 6–10 weeks, source code yours. You've seen what it takes; we do it every week.

Get a fixed-price quote

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.