whisper.rn: running whisper.cpp and Parakeet ASR inside a React Native app
React Native binding of whisper.cpp.
At a glance
- What is it?
- whisper.rn wraps whisper.cpp as a React Native module, adding a Parakeet TDT context, Silero VAD and a realtime transcriber on top. It is a good fit when audio must stay on the device; the audio format rules and the model download problem are where teams get stuck.
- Who is it for?
- Adopt whisper.rn if you need speech recognition that never leaves the phone and your input is already WAV, 16-bit PCM, mono at 16 kHz, or can be converted before it reaches the library. Do not adopt it if you need MP3, AAC or FLAC decoded for you, or if you expect the package to ship a model; the README has the example app downloading GGUF files at runtime because they are too large to bundle.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What whisper.rn solves for React Native teams
Speech recognition in a mobile app usually means shipping audio to a server and paying for the round trip in latency, bandwidth and privacy exposure. whisper.rn takes the other route. It is a React Native binding of whisper.cpp, the C++ implementation of OpenAI's Whisper ASR model, so inference runs on the device inside your existing JavaScript app. The package description is exactly that: "React Native binding of whisper.cpp."
The audience is narrow and identifiable. You are building a React Native or Expo app, you already accept a native dependency, and you have a reason to keep audio local: offline dictation, meeting notes that cannot leave the handset, or transcription of files the user picked from their own storage. The README shows the intended shape of the API in a few lines, and the whole surface is promise based, which fits the rest of a React Native codebase without a separate threading model.
Newer releases go beyond Whisper. The README documents a ParakeetContext that runs NVIDIA's Parakeet TDT 0.6B v3 model through the Parakeet API included in whisper.cpp, and states that v3 covers English plus 24 other European languages. That matters because Whisper and Parakeet have different accuracy and speed profiles, and the binding lets you pick per feature rather than per app.
How the binding reaches whisper.cpp and what the data flow looks like
The repository layout tells most of the story. There is a cpp/ directory, a cmake/ directory, a vendor/ directory, an android/ directory, an ios/ directory and a whisper-rn.podspec at the top level. The package.json files field ships src, lib, android, cpp, ios, cmake, vendor and the podspec, while explicitly excluding android/src/main/jniLibs and android/.cxx. So the published artifact carries the native sources and build files, not prebuilt Android binaries, and the iOS side is described in the README as using a pre-built rnwhisper.xcframework unless you opt into a source build.
At runtime the flow is short. You call initWhisper with a file path to a ggml model, you get a context back, and you call transcribe on it with an audio file path and options. The README example passes language: 'en' and destructures stop and promise from the call. The promise resolves to an object containing result, the inference text. Nothing in that path is a network call unless you make it one.
The Parakeet path mirrors this with initParakeet, which takes a filePath and useGpu, and returns a context whose transcribe call accepts options such as maxThreads. Its result object exposes result, segments and isAborted, and the context has a release method. That is a slightly richer contract than the Whisper example, and it is the one to read if you care about aborting a long job.
The VAD side is separate. initWhisperVad loads a Silero VAD model, and the context exposes detectSpeech for files, HTTP URLs, base64 WAV and bundled assets, plus detectSpeechData for raw audio. Segments come back with t0 and t1 timestamps in seconds. VAD is the piece that makes auto-slicing possible, because you can find speech boundaries before handing audio to a recognizer.
Installing whisper.rn and running a first transcription
Installation starts with a single npm command. The README gives it plainly, and there is no separate CLI or codegen step described.
npm install whisper.rnOn iOS the README says to re-run npx pod-install. By default the package uses the pre-built rnwhisper.xcframework; if you want to compile the native code yourself you set RNWHISPER_BUILD_FROM_SOURCE to 1 in your Podfile. The README also recommends enabling the Extended Virtual Addressing capability on iOS projects when you plan to use the medium or large models, which is a hint about how much address space the larger weights want.
npx pod-installOn Android, if ProGuard is enabled, the README asks for a keep rule in android/app/proguard-rules.pro so the binding's classes survive shrinking.
# whisper.rn
-keep class com.rnwhisper.** { *; }The README recommends ndkVersion = "24.0.8215888" or above in the root project build configuration, specifically for Apple Silicon Macs, and points at a troubleshooting entry for the "unknown host CPU architecture arm64" error when that is not set. Expo users are told to prebuild the project before using the library, with a link to Expo's own guide on using libraries in an Expo project.
Once the native side builds, the first real use is short. You need a ggml model file on disk or in your bundle, then you initialize a context and transcribe a WAV file.
import { initWhisper } from 'whisper.rn'
const whisperContext = await initWhisper({
filePath: 'file://.../ggml-tiny.en.bin',
})
const sampleFilePath = 'file://.../sample.wav'
const options = { language: 'en' }
const { stop, promise } = whisperContext.transcribe(sampleFilePath, options)
const { result } = await promiseThe variable named result is the inference text for that audio file. Note that the model is not downloaded by the library; you supply the path. The README does not document where to obtain Whisper ggml models, so treat model acquisition as your own step.
The audio format rule that decides whether Parakeet works for you
This is the constraint most likely to derail a first integration. The README states that Parakeet file and base64 inputs must be WAV containing 16-bit PCM audio, that transcribeData accepts raw signed 16-bit PCM as a base64 string or an ArrayBuffer, and that raw audio must be mono at 16 kHz. It then says directly that compressed formats such as MP3, AAC and FLAC are not decoded.
So the library is not a media pipeline. If your users record voice memos in AAC, or pick MP3s from a music folder, you need a decoding step before whisper.rn sees the data, and that step is outside this package. The VAD documentation is more permissive about inputs (it lists file paths, HTTP URLs, base64 WAV and bundled assets) but it does not claim compressed-format support either.
The second constraint is size. The README's Parakeet table lists GGUF variants from 356 MB for ggml-parakeet-tdt-0.6b-v3-q4_0.bin up to 1.26 GB for the f16 build, and explains that the example app downloads these models at runtime because they are too large to bundle comfortably. A 356 MB download on first launch is a product decision, not a technical one, and the library does not make it for you. Whisper models are not sized in the README at all, which leaves you to work that out from whisper.cpp's own documentation.
Where whisper.rn is the wrong tool
If your transcription happens on a server you control, this binding adds a native dependency, a build toolchain and a model download for no benefit. A REST call to a hosted ASR endpoint is simpler to ship and simpler to update, because the model improves without an app store release.
If you need diarization, word-level timestamps beyond what segments give you, or a language set larger than Whisper and Parakeet cover, the README does not describe those capabilities, and you should assume they are absent rather than hoped for. The binding exposes what whisper.cpp exposes.
If your team cannot own the native build, this is a poor fit. The README's own instructions involve a Podfile variable, a ProGuard rule, an ndkVersion recommendation and an Expo prebuild step. Every one of those is a place where a JavaScript-only contributor will need help. And if your target devices are memory constrained, the larger Parakeet and Whisper variants are simply not available to you; the iOS Extended Virtual Addressing recommendation exists for exactly that reason.
How whisper.rn differs from a cloud ASR API and from whisper.cpp directly
The closest alternative is a hosted speech-to-text API. The difference is architectural rather than qualitative. A hosted API gives you format handling, model updates and scaling for free, and charges per minute with a network dependency. whisper.rn gives you offline operation and no per-minute cost, and charges you in binary size, build complexity and the audio conversion work the README says it does not do. Neither is better in the abstract; the deciding question is whether audio is allowed to leave the device.
The other comparison is whisper.cpp itself. whisper.rn is a binding, not a fork of the inference engine: the repository vendors whisper.cpp and adds a React Native module layer, a TypeScript API, a realtime transcriber and the VAD wrapper. If your app is native Swift or Kotlin, you would use whisper.cpp directly and skip the JavaScript bridge entirely. The binding earns its place only when React Native is already your stack and you want the recognizer available from TypeScript without writing a native module yourself.
Within the binding, the Whisper and Parakeet paths are themselves alternatives. Whisper has the broader model lineage; Parakeet TDT 0.6B v3 is documented as English plus 24 other European languages, with quantized GGUF builds and a useGpu flag. Which one wins on your audio is not something the README answers, and it is worth measuring on your own recordings before committing to a model size.
Maintenance, releases and the MIT licence
The repository is not archived, and the last push was on 2026-09-14. Release cadence has been steady: v0.7.2 on 2026-07-24, v0.7.3 on 2026-08-24 and v0.7.4 on 2026-08-27. The package.json version matches the newest release at 0.7.4, which means the published npm artifact and the tagged release are in step.
Upgrade cost is concentrated in the native layer. Because the package ships cpp, cmake, vendor, ios and android sources, a version bump can change what gets compiled, and the README's guidance about RNWHISPER_BUILD_FROM_SOURCE, the ProGuard keep rule and the recommended ndkVersion is the checklist to revisit each time. The package also runs a docgen step before build in its prepack script, so the published TypeScript types track the source API rather than drifting from it.
The licence is MIT, declared in the repository and in the badge at the top of the README. MIT is permissive and imposes no source-disclosure obligation on your app. What it does not do is resolve the model licences: Whisper weights, Parakeet weights and the Silero VAD model come from separate projects with their own terms, and the README does not discuss them. Check those separately before shipping a model inside your binary.
Editorial conclusion
Adopt whisper.rn if you need speech recognition that never leaves the phone and your input is already WAV, 16-bit PCM, mono at 16 kHz, or can be converted before it reaches the library. Do not adopt it if you need MP3, AAC or FLAC decoded for you, or if you expect the package to ship a model; the README has the example app downloading GGUF files at runtime because they are too large to bundle. Verify three things first: that your Podfile and Gradle setup match the iOS source-build flag and the recommended ndkVersion, that your chosen model size fits the memory budget on your lowest-end target device, and that your transcription path handles the stop and release calls the API returns.
Frequently asked questions
How do I install whisper.rn in a React Native project?
Run npm install whisper.rn, then re-run npx pod-install on iOS. Android projects with ProGuard enabled need the keep rule for com.rnwhisper documented in the README, and the README recommends ndkVersion 24.0.8215888 or above for Apple Silicon Macs.
Does whisper.rn work with Expo?
Yes, but the README says you need to prebuild the project before using the library, and links to Expo's guide on using libraries in an Expo project. It does not claim support for Expo Go.
Where do the whisper.rn models come from?
The library does not supply them. You pass a filePath to a ggml model when calling initWhisper, and for Parakeet you download a GGUF model from ggml-org/parakeet-GGUF before initializing the context.
Which audio formats can whisper.rn transcribe?
For Parakeet, the README states that file and base64 inputs must be WAV containing 16-bit PCM, and that raw audio must be mono at 16 kHz; MP3, AAC and FLAC are not decoded. The whisper.cpp side supports the formats whisper.cpp itself supports, which the README does not enumerate.
Can whisper.rn transcribe in real time?
The README documents a RealtimeTranscriber that provides realtime transcription with Voice Activity Detection, auto-slicing and memory management. The section is truncated in the README, so read the linked docs for the full API.
Community notes