LLM Guides

How to Convert Speech to Text with JavaScript

Jun 27, 2026

Speech-to-text sounds simple from the outside: user speaks, app shows text.

In JavaScript, the real choice is how you want that speech to become text. You can use the browser’s built-in speech recognition for quick dictation. You can record audio in the browser and send it to a transcription API. You can build a real-time voice app with streaming. Or you can send the transcript into an AI workflow that cleans it, summarizes it, classifies it, or stores it.

This guide walks through the practical paths, with code examples and simple advice on when each one makes sense.

Start with the use case

Before writing code, pick the speech-to-text path that matches the product.

Use caseBest JavaScript pathWhy
Quick browser dictationWeb Speech APIFast to build, no backend needed
Voice note uploadMediaRecorder + transcription APIBetter control and more reliable output
Meeting recorderRecord audio, send file to APIEasier than live streaming
Live captionsStreaming speech-to-text APILower latency and partial results
Voice agentRealtime audio sessionNeeded when the app listens and responds
Private internal workflowBackend transcription APIKeeps API keys and logs under control

For a small demo, the browser-native route is fine. For a real product, recording audio and sending it to a transcription API is usually easier to manage.

Why we can write this guide

We have around 6 years of experience working with AI APIs, developer tools, automation workflows, and content systems. We also researched current browser APIs, speech-to-text providers, and automatic speech recognition research before writing this.

The main thing we found: speech-to-text quality depends on the full workflow. The model matters, but so do audio quality, microphone access, browser support, latency, file format, language, accents, background noise, and what you do with the transcript after.

The Whisper research paper is a useful example. It showed that large-scale weak supervision across 680,000 hours of multilingual audio can improve robustness across different speech conditions. For developers, the practical lesson is simple: modern transcription models are much better than older systems, but your app still needs good audio handling and smart fallback logic.

Path 1: Use the browser’s web speech API

The fastest way to convert speech to text with JavaScript is the Web Speech API.

MDN describes the Web Speech API as a browser API for speech recognition and speech synthesis. The recognition part is handled through SpeechRecognition.

This is good for:

Good fitWeak fit
Small demosProduction apps that need consistent browser support
Dictation fieldsSensitive audio workflows
Voice commandsLong recordings
Internal toolsOffline transcription

There is one important catch. MDN marks SpeechRecognition as limited availability because it does not work in every major browser. MDN also notes that some browsers may send audio to a server-based recognition service, so you should review privacy needs before using it.

Here is a simple browser example.

<button id="start">Start speaking</button>
<button id="stop">Stop</button>

<p><strong>Live text:</strong></p>
<div id="output"></div>

<script>
  const SpeechRecognition =
    window.SpeechRecognition || window.webkitSpeechRecognition;

  const output = document.getElementById("output");
  const startButton = document.getElementById("start");
  const stopButton = document.getElementById("stop");

  if (!SpeechRecognition) {
    output.textContent = "Speech recognition is not supported in this browser.";
  } else {
    const recognition = new SpeechRecognition();

    recognition.lang = "en-US";
    recognition.continuous = true;
    recognition.interimResults = true;

    recognition.onresult = (event) => {
      let transcript = "";

      for (let i = 0; i < event.results.length; i++) {
        transcript += event.results[i][0].transcript;
      }

      output.textContent = transcript;
    };

    recognition.onerror = (event) => {
      output.textContent = `Error: ${event.error}`;
    };

    startButton.addEventListener("click", () => {
      recognition.start();
    });

    stopButton.addEventListener("click", () => {
      recognition.stop();
    });
  }
</script>

This gives you a working speech-to-text demo in a few minutes. It is the easiest option for a tutorial, a prototype, or a local admin tool.

For a user-facing product, test it across your target browsers first. Browser support and recognition behavior can change the user experience a lot.

Path 2: Record audio in the browser

The next path is more flexible:

  1. Ask the user for microphone access.
  2. Record audio in the browser.
  3. Send the audio file to your backend.
  4. Transcribe it with an API.
  5. Return the transcript to the frontend.

This gives you more control than browser-native recognition.

The main browser API here is MediaRecorder. MDN describes it as part of the MediaStream Recording API, used to record media from a stream. MDN also notes that it has been broadly available across browsers since April 2021, though some details can vary by browser.

Here is a simple recorder.

<button id="record">Start recording</button>
<button id="stop" disabled>Stop recording</button>

<audio id="player" controls></audio>
<pre id="status"></pre>

<script>
  const recordButton = document.getElementById("record");
  const stopButton = document.getElementById("stop");
  const player = document.getElementById("player");
  const statusBox = document.getElementById("status");

  let mediaRecorder;
  let audioChunks = [];

  recordButton.addEventListener("click", async () => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });

    mediaRecorder = new MediaRecorder(stream);
    audioChunks = [];

    mediaRecorder.addEventListener("dataavailable", (event) => {
      audioChunks.push(event.data);
    });

    mediaRecorder.addEventListener("stop", async () => {
      const audioBlob = new Blob(audioChunks, { type: "audio/webm" });
      const audioUrl = URL.createObjectURL(audioBlob);

      player.src = audioUrl;
      statusBox.textContent = "Recording ready.";

      await sendAudioToServer(audioBlob);
    });

    mediaRecorder.start();

    recordButton.disabled = true;
    stopButton.disabled = false;
    statusBox.textContent = "Recording...";
  });

  stopButton.addEventListener("click", () => {
    mediaRecorder.stop();

    recordButton.disabled = false;
    stopButton.disabled = true;
  });

  async function sendAudioToServer(audioBlob) {
    const formData = new FormData();
    formData.append("audio", audioBlob, "recording.webm");

    const response = await fetch("/api/transcribe", {
      method: "POST",
      body: formData
    });

    const data = await response.json();
    statusBox.textContent = data.text;
  }
</script>

This creates an audio blob in the browser and sends it to /api/transcribe.

Keep API keys out of frontend code. The browser should record audio, then your backend should call the transcription provider.

Path 3: Transcribe the recording with OpenAI

OpenAI’s current speech-to-text docs list the transcriptions endpoint for converting audio into text. The docs also list supported upload formats including mp3, mp4, mpeg, mpga, m4a, wav, and webm, with a 25 MB file upload limit.

The docs currently show gpt-4o-transcribe, gpt-4o-mini-transcribe, and gpt-4o-transcribe-diarize as transcription model options. The diarization model is useful when you need speaker labels.

Here is a simple Node.js backend route.

npm install express multer openai

import express from "express";
import multer from "multer";
import fs from "node:fs";
import { unlink } from "node:fs/promises";
import OpenAI from "openai";

const app = express();
const upload = multer({ dest: "uploads/" });
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY
});

app.post("/api/transcribe", upload.single("audio"), async (req, res) => {
  try {
    const transcription = await openai.audio.transcriptions.create({
      file: fs.createReadStream(req.file.path),
      model: "gpt-4o-transcribe"
    });

    await unlink(req.file.path);

    res.json({ text: transcription.text });
  } catch (error) {
    if (req.file?.path) {
      await unlink(req.file.path).catch(() => {});
    }

    res.status(500).json({
      error: "Transcription failed"
    });
  }
});

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000");
});

This is the cleanest beginner-friendly architecture:

Browser microphone → MediaRecorder → Audio Blob → Backend upload route → Transcription API → Text returned to frontend

For many apps, this is enough.

Path 4: Use streaming for live transcription

File transcription works well for recordings. Streaming is better when the user needs live feedback.

OpenAI’s audio guide separates request-based audio APIs from realtime sessions. Request-based APIs are simpler for completed files. Realtime sessions are better when audio is live and the app needs low-latency events.

Deepgram’s speech-to-text docs describe a similar split: streaming audio for voice agents, realtime transcription for meetings and events, and pre-recorded audio for uploaded files.

Use streaming for:

Use caseWhy streaming helps
Live captionsUsers see partial text quickly
Voice agentsThe app can detect when the user stops speaking
Call center toolsAgents can see text during the call
Meeting assistantsNotes can appear while people talk
Accessibility toolsLow latency matters

Use file transcription for:

Use caseWhy file transcription works
Voice notesUser can wait a few seconds
PodcastsAccuracy matters more than instant output
InterviewsPost-processing is normal
Uploaded lecturesLong-form processing is expected
Internal reportsBatch workflows are easier

A simple rule: if the user is watching the transcript appear, use streaming. If the user uploads or records something and waits, use file transcription.

Choosing the right speech-to-text setup

Here is the practical choice map.

If you need…Choose…
Fastest demoWeb Speech API
Better accuracy and controlMediaRecorder + transcription API
No backendWeb Speech API
Secure API key handlingBackend transcription route
Long recordingsFile upload transcription
Live captionsStreaming API
Speaker labelsDiarization-capable model
Multilingual transcriptionModern STT model with language support
Voice agentRealtime audio session
Transcript cleanupSTT + LLM post-processing

The Conformer paper is useful background here because it showed how combining convolution and transformer layers can improve speech recognition. The practical takeaway: speech recognition models are designed to capture both local sound patterns and longer context. That is why modern APIs often do better when the audio has enough context, clean input, and domain hints.

Improving transcript quality

Bad audio makes every speech-to-text system worse. Good code helps, but the microphone and recording conditions matter too.

Use this checklist before blaming the model:

CheckWhy it matters
Use a decent microphoneBuilt-in laptop mics pick up room noise
Reduce background noiseNoise can create wrong words
Avoid overlapping speakersSpeaker overlap is hard to transcribe
Set the correct languageHelps names, spelling, and punctuation
Keep recordings focusedShorter clips are easier to debug
Add domain contextProduct names and acronyms need help
Use diarization for meetingsSpeaker labels need model support
Store raw audio temporarilyHelps debug bad transcripts
Keep user consent clearVoice data can be sensitive

OpenAI’s speech-to-text docs mention that prompts can help transcription quality for specific words, acronyms, punctuation style, or segmented files. That is useful for apps with brand names, medical terms, legal terms, internal product names, or uncommon spellings.

Example:

const transcription = await openai.audio.transcriptions.create({
  file: fs.createReadStream("sales-call.webm"),
  model: "gpt-4o-transcribe",
  prompt: "The transcript may mention LLMAPI, SOC 2, SSO, RAG, embeddings, and model routing."
});

This does not guarantee perfect spelling, but it gives the model useful context.

Add transcript cleanup

Raw transcripts are often messy. People pause, repeat themselves, change direction, and use filler words.

After transcription, you can send the text to an LLM for cleanup.

Common cleanup tasks include:

TaskExample
Remove filler wordsClean meeting notes
Add punctuationMake transcript readable
SummarizeCreate short notes
Extract action itemsTurn calls into tasks
Classify intentRoute support messages
Detect languageStore transcripts by language
Create titlesName voice notes automatically
Generate chaptersSplit podcasts or lectures

A simple workflow can look like this:

Audio recording → Speech-to-text API → Raw transcript → LLM cleanup step → Summary, tags, action items, or structured data

This is where LLMAPI can fit well. You can use one workflow to transcribe the audio, then route the transcript to another model for summary, classification, moderation, translation, or formatting.

For example:

Customer call audio → Transcription → LLMAPI workflow → Summary + sentiment + action items → CRM record

That setup is useful for sales calls, support tickets, meeting assistants, training tools, voice notes, and internal search.

Privacy and security basics

Speech data can contain names, addresses, payment details, medical information, legal information, workplace details, or private conversations.

For a real app, use these rules:

RuleWhy
Ask clearly before recordingMicrophone access needs user consent
Keep API keys on the backendFrontend keys can be copied
Delete temporary filesAudio files are sensitive
Review provider retention termsSome apps need strict data rules
Log carefullyTranscripts can contain private data
Add upload limitsPrevents huge files and surprise costs
Show recording stateUsers should know when the mic is active

Also check local laws if you record calls or meetings. Consent rules vary by location and use case.

Full beginner workflow

Here is the simplest production-style version:

  1. User clicks “Record.”
  2. Browser asks for microphone access.
  3. MediaRecorder records audio.
  4. Browser sends recording.webm to your backend.
  5. Backend sends the file to a speech-to-text API.
  6. Backend returns the transcript.
  7. Optional LLM step cleans or summarizes the transcript.
  8. App displays or stores the final text.

That gives you a clean split:

LayerResponsibility
BrowserRecord audio and show transcript
BackendProtect API keys and call transcription provider
STT APIConvert audio to text
LLM layerClean, summarize, classify, or format
DatabaseStore transcript and metadata

Common problems

SpeechRecognition is undefined

The browser does not support the Web Speech API.

Use this fallback:

const SpeechRecognition =
  window.SpeechRecognition || window.webkitSpeechRecognition;

if (!SpeechRecognition) {
  console.log("Use audio recording and backend transcription instead.");
}

The browser blocks microphone access

Use HTTPS in production. Browsers usually require secure contexts for microphone access.

The transcript is inaccurate

Check the audio first. Then check language, microphone quality, background noise, and domain vocabulary.

The uploaded file is too large

Compress audio, set recording limits, or split long recordings into smaller chunks. OpenAI’s speech-to-text docs currently list a 25 MB upload limit for file transcription.

The API key is exposed

Move transcription to the backend. The frontend should never call paid transcription APIs directly with a private key.

Final code structure

For a small app, this structure works well:

project/

  server.js

  package.json

  public/

    index.html

Frontend:

public/index.html

Records audio with MediaRecorder, then uploads it.

Backend:

server.js

Receives the file, sends it to the transcription API, returns JSON.

This keeps the build simple and avoids frontend key leaks.

Final thoughts

JavaScript gives you several good ways to convert speech to text.

Use the Web Speech API when you want a fast browser demo or simple dictation. Use MediaRecorder plus a transcription API when you want better control, stronger accuracy, and a setup that can grow into a real app. Use streaming when users need live captions, voice agents, or real-time call transcription.

The best path depends on the workflow. For a five-minute demo, browser recognition is enough. For a real product, record audio in the browser, send it to your backend, transcribe it with a reliable API, then use an LLM step to clean or structure the result.

That gives you a speech-to-text workflow that is simple, practical, and ready for useful features like summaries, action items, tags, search, and automation.

Deploy in minutes