HomeBlog → How to record audio in the browser and turn it into text

How to record audio in the browser and turn it into text

Published 2026-08-20 · 5 min read

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

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 key

Frequently 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