New Voice Standard Bench: 50+ LLMs ranked on real voice tasks Learn more
Insights & Use Cases

How to transcribe audio from a mobile app (iOS/Swift, Android/Kotlin, React Native)

There's no AssemblyAI mobile SDK — and you shouldn't ship your API key to a phone anyway. This tutorial shows the right pattern: a thin backend proxy plus lightweight Swift, Kotlin, and React Native clients that record audio and call your server, never AssemblyAI directly.

Abstract green cylinder illustration

Written by

Kelsey Foster

Published on

22 July 2026

If you searched for an AssemblyAI mobile SDK, here's the short version: there isn't one. The official SDKs are Python (pip install assemblyai) and JavaScript/TypeScript (npm install assemblyai). No Swift, no Kotlin, no React Native package.

That's not the problem you think it is. The bigger constraint is security: don't ship your API key to client-side code. A mobile binary can be decompiled, and anyone who pulls your key out of it can spend your account balance. So even if a native SDK existed, calling AssemblyAI directly from a phone would be the wrong move.

The right pattern is a thin backend you control. Your mobile app records audio and sends it to your server. Your server holds the API key, talks to AssemblyAI over the REST API, and returns plain text. That's the whole lesson, and it's a good one—you get key security, request logging, rate limiting, and the freedom to swap models later without shipping a new app build.

Here's what you'll build:

  • A backend (Node or Python) that receives an audio file, uploads it to AssemblyAI, creates a transcript, polls for the result, and returns the text.
  • Three thin clients—Swift, Kotlin, and React Native—that record audio and call your backend, never AssemblyAI.

Prerequisites

  • An AssemblyAI account and API key. Get your free API key from the dashboard.
  • Node 18+ or Python 3.8+ for the backend.
  • Xcode for iOS, Android Studio for Android, or a React Native toolchain—whichever platforms you're targeting.

If you're new to the API, the transcribe an audio file quickstart covers the async flow end to end. This tutorial adapts it for mobile.

Architecture overview

One rule shapes everything: the API key lives on the server, and only the server talks to AssemblyAI.

Note what's not in the diagram: the mobile client never sees the API key and never has AssemblyAI's URL. It only knows about your endpoint. If you rotate the key or change models, the app doesn't change.

Why a backend proxy specifically? For pre-recorded audio there's no temporary-token mechanism—temporary tokens exist only for streaming. So for file transcription, the key has to live somewhere trusted, and that's your server.

Start With a Free API Key

The backend proxy pattern needs one thing to get going: your key, safe on the server. Grab a free API key and wire up the three-call async flow in minutes.

Sign up free

The AssemblyAI async flow

Everything the backend does is three REST calls against https://api.assemblyai.com. Auth is your API key in the authorization header—no Bearer prefix.

  1. Upload (optional): POST /v2/upload with the raw audio bytes as the body. Returns { "upload_url": "..." }. Skip this if your audio already lives at a public URL.
  2. Create transcript: POST /v2/transcript with JSON { "audio_url": "..." }. Returns a transcript object with an id and a status.
  3. Get result: GET /v2/transcript/{id}. Poll every few seconds until status is completed or error.

The status lifecycle is queued → processing → completed (or error).

One gotcha that bites people on the upload step: the body must be raw bytes, not JSON. If you send a JSON envelope, the upload appears to succeed but transcription fails later with "Transcoding failed." Send the file bytes directly.

Backend implementation

Pick your language. Both versions expose a single POST /transcribe endpoint that accepts a multipart file upload from the mobile client and returns { "text": "..." }. Both read the API key from an environment variable—never hardcode it.

Node (Express)


Python (FastAPI)

Run it with uvicorn main:app --port 8080.

A few production notes that apply to both:

  • Polling vs. webhooks. Polling every 3 seconds is simple and fine for short clips. For longer audio, hold the HTTP connection open only if your infra tolerates it—otherwise return the transcript id immediately and let the client poll a GET /transcribe/{id} route, or register a webhook so AssemblyAI notifies you when the job finishes.
  • Limits. The upload endpoint accepts files up to 2.2 GB. The transcript request body caps at 5 GB, and audio duration must be between 160ms and 10 hours.
  • Add features here, not on the client. Want speaker labels or summarization? Add the options to the /v2/transcript JSON body server-side. The app doesn't change.

For every field you can pass, see the submit transcript reference, the upload reference, and the get transcript reference.

Client implementations

All three clients do the same three things: record audio to a file, POST that file to your backend as multipart form data, and show the returned text. None of them know AssemblyAI exists.

Set BACKEND_URL to wherever your server runs. Use http://localhost:8080 for a simulator, or your machine's LAN IP for a physical device.

iOS / Swift

Record with AVAudioRecorder, then upload with URLSession. Add NSMicrophoneUsageDescription to your Info.plist first.

No API key anywhere. The client's entire world is backendURL.

Android / Kotlin

Record with MediaRecorder, upload with OkHttp. Declare RECORD_AUDIO in your manifest and request it at runtime.


Call stopAndTranscribe() off the main thread (a coroutine on Dispatchers.IO works well).

React Native

Record with a library like react-native-audio-recorder-player, then upload with the built-in fetch and FormData:

Because JavaScript is a first-class citizen here, you might be tempted to reach for the assemblyai npm package inside your React Native app. Don't. The Node SDK is built for server environments, and using it on the client means embedding your API key in the bundle—the exact thing we're avoiding. The fetch-to-your-backend pattern above is the correct one for React Native.

Hear the Transcript Before You Build

Drop in a sample clip and see the async output your backend will return — speaker labels, summaries, and more, all as server-side options your app gets for free.

Try playground

Testing and validation

Test the backend on its own before wiring up a phone. Record or grab any short audio file and hit the endpoint with curl:

You should get back {"text":"..."} within a few seconds for a short clip. If you don't:

  • "Transcoding failed" almost always means the upload body wasn't raw bytes. Confirm you're sending the buffer/bytes directly, not a JSON wrapper.
  • 401 Unauthorized means the authorization header is missing or wrong. Check that ASSEMBLYAI_API_KEY is set in the server's environment—and remember, no Bearer prefix.
  • The request hangs on long audio because polling holds the connection open. Switch to the return-id-and-poll pattern or a webhook.

Once curl works, point the app at the backend. On a physical device, localhost won't resolve to your dev machine—use its LAN IP (for example http://192.168.1.20:8080/transcribe), and on Android the emulator reaches the host at 10.0.2.2.

Realtime from mobile (next step)

If you need live captions instead of file-at-a-time transcription, AssemblyAI has a streaming API over WebSocket at wss://streaming.assemblyai.com/v3/ws. There's still no mobile-native streaming SDK, but streaming has something file transcription doesn't: short-lived tokens.

Your backend calls GET /v3/token?expires_in_seconds=60 (tokens last 1–600s and are single-use), hands the token to the app, and the app opens the WebSocket with the token as a token query param. The key still never leaves your server; the token is safe to give the client because it expires fast and works once. Audio goes up as mono 16-bit PCM.

That flow is documented in authenticate with a temporary token. For a working streaming client to model your backend on, see real-time transcription in Python.

Next steps

You now have a mobile transcription pipeline that keeps your API key where it belongs. From here:

  • Add speech understanding. Speaker diarization, summarization, and more are options on the /v2/transcript body—turn them on server-side and your app gets them for free. Start with what is speech-to-text and the Speech-to-Text product page.
  • Harden the backend. Add authentication on your /transcribe route, rate limiting, and request logging—the proxy is the natural place for all of it.
  • Explore every parameter. The full API reference documents the complete transcript object.

Get your free API key and ship it.

Ship Your Mobile Transcription Pipeline

You've got a pattern that keeps your API key where it belongs. Get a free API key, harden the proxy, and ship transcription on iOS, Android, or React Native.

Get your free API key

Frequently asked questions

Is there an official AssemblyAI iOS or Android SDK?

No. The only official SDKs are Python (pip install assemblyai) and JavaScript/TypeScript (npm install assemblyai). For mobile, call the REST API at https://api.assemblyai.com from a backend you control.

Can I call the AssemblyAI API directly from my mobile app?

Technically the REST API works from anywhere, but you shouldn't. Calling it directly means embedding your API key in the app binary, where it can be extracted. Route every request through your own backend instead.

How do I keep my API key safe in a mobile app?

Never ship it to the client. Store it as an environment variable on your server, have the app send audio to your backend, and let the backend attach the authorization header when it calls AssemblyAI. That's the architecture in this tutorial.

Does AssemblyAI support React Native?

There's no React Native SDK. Use fetch with FormData to send audio to your backend, exactly like the web. Avoid the assemblyai npm package on the client—it's a server SDK and would expose your key.

Can I do realtime transcription on mobile?

Yes, over the streaming WebSocket at wss://streaming.assemblyai.com/v3/ws. There's no mobile streaming SDK, so your backend mints a one-time token via GET /v3/token?expires_in_seconds=60 and the app connects with it. Audio is mono 16-bit PCM. See the temporary token docs.

What are the file size and duration limits?

The upload endpoint accepts files up to 2.2 GB. The transcript request body caps at 5 GB, and audio must run between 160ms and 10 hours.