Home → Blog → How to record audio in the browser and turn it into text
How to record audio in the browser and turn it into text
Voice input pays off wherever typing is slow: support tickets from a phone, comments in a field, dictating a long description. The browser records audio with built-in APIs, and transcription is one request away — from your server, not from the page. Here is the working pattern.
Recording in the browser
The built-in MediaRecorder produces a finished file with no libraries:
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const rec = new MediaRecorder(stream, { mimeType: "audio/webm" });
const chunks = [];
rec.ondataavailable = e => chunks.push(e.data);
rec.onstop = async () => {
const blob = new Blob(chunks, { type: "audio/webm" });
const form = new FormData();
form.append("file", blob, "voice.webm");
const r = await fetch("/api/transcribe", { method: "POST", body: form });
document.querySelector("#out").value = (await r.json()).text;
};
rec.start();
setTimeout(() => rec.stop(), 15000);
webm is accepted directly, so there is nothing to convert.
Why the key never belongs in the browser
It is tempting to post the file straight from the page, but then your key sits in source anyone can read. Within an hour it is found; within a day the balance is gone.
The correct shape is a thin proxy on your own server: the browser uploads to you, you check the user and their quota, and only your server talks to the API with the key.
The server-side proxy
import express from "express";
import multer from "multer";
import OpenAI from "openai";
import { toFile } from "openai/uploads";
const upload = multer({ limits: { fileSize: 25 * 1024 * 1024 } });
const client = new OpenAI({ baseURL: "https://voicesscribe.com/v1", apiKey: process.env.VS_KEY });
express()
.post("/api/transcribe", upload.single("file"), async (req, res) => {
const file = await toFile(req.file.buffer, "voice.webm");
const r = await client.audio.transcriptions.create({ model: "whisper-1", file });
res.json({ text: r.text });
})
.listen(3000);
This is also where you cap recording length and per-user request counts — otherwise the first bot that finds the form turns it into your expense.
Browser limitations
- HTTPS only. Microphone access is not granted over plain HTTP, except on localhost during development.
- Explicit permission. Recording starts only after the user agrees, so request it on a button press, not on page load.
- Different containers. Some browsers record webm, others mp4 — both are accepted, but set the filename from the actual type.
- Background tabs. On mobile, recording stops when the tab is backgrounded, so long dictation is unreliable.
Try it on your own recordings. Sign-up takes a minute, and the free minutes are enough to judge the quality.
Get a free API keyFrequently asked questions
Can I call the API directly from the browser?
Technically yes, but the key becomes visible to every visitor. Always put a proxy on your own server.
Do I need to convert webm?
No, the format is accepted as is. Just pass a filename with the right extension.
Can I show text while the user is still speaking?
There is no streaming output: the text returns after processing. For a live feel, cut the recording into short chunks and send them in sequence.
What about the length limit?
25 MB per file, which is hours of speech in webm — not a practical constraint for voice input.
Related reading
- Speech to text in Node.js: working code and the usual pitfalls — How to transcribe audio from Node.js: the official SDK, streams and FormData, handling uploads in Express, timeouts and retries — with code you can paste.
- How to turn voice notes into text automatically — Turn phone and recorder voice notes into a searchable knowledge base: a synced folder, a watcher script, a note template and tips for messy field audio.
- Transcription privacy and security: what to check with a provider — Five questions to ask a speech recognition provider: retention, training on your data, channel encryption, staff access and deletion on request.