react-nativeRhino - React Native API

  • Speech-to-Intent Engine
  • Domain Specific NLU
  • Offline NLU
  • Local Voice Recognition
  • React Native
  • JavaScript
  • Mobile
  • Android
  • iOS

This document outlines how to integrate Rhino Speech-to-Intent engine within an application using its React Native API.


  • Node
  • yarn or npm
  • CocoaPods
  • Android SDK 16+
  • JDK 8+
  • Xcode 9+

Refer to React Native's environment setup page for specifics on how to prepare your machine for React Native development.


  • React Native 0.62.2+
  • Android 4.1+ (API 16+)
  • iOS 9.0+


To install Porcupine into you React Native project add the following native modules to your project:

yarn add @picovoice/react-native-voice-processor
yarn add @picovoice/rhino-react-native


npm i @picovoice/react-native-voice-processor --save
npm i @picovoice/rhino-react-native --save

Link the iOS package

cd ios && pod install && cd ..

NOTE: Due to a limitation in React Native CLI autolinking, these two native modules cannot be included as transitive dependencies. If you are creating a module that depends on rhino-react-native and/or react-native-voice-processor, you will have to list these as peer dependencies and require developers to install them alongside.


To enable recording with the hardware's microphone, you must first ensure that you have enabled the proper permission on both iOS and Android.

On iOS, open your Info.plist and add the following line:

<string>[Permission explanation]</string>

On Android, open your AndroidManifest.xml and add the following line:

<uses-permission android:name="android.permission.RECORD_AUDIO" />

Finally, in your app JS code, be sure to check for user permission consent before proceeding with audio capture:

let recordAudioRequest;
if (Platform.OS == 'android') {
// For Android, we need to explicitly ask
recordAudioRequest = this._requestRecordAudioPermission();
} else {
// iOS automatically asks for permission
recordAudioRequest = new Promise(function (resolve, _) {
recordAudioRequest.then((hasPermission) => {
// Code that uses Rhino
async _requestRecordAudioPermission() {
const granted = await PermissionsAndroid.request(
title: 'Microphone Permission',
message: '[Permission explanation]',
buttonNeutral: 'Ask Me Later',
buttonNegative: 'Cancel',
buttonPositive: 'OK',
return (granted === PermissionsAndroid.RESULTS.GRANTED)


The module provides you with two levels of API to choose from depending on your needs.

High-Level API

RhinoManager provides a high-level API that takes care of audio recording. This class is the quickest way to get started.

The constructor RhinoManager.create will create an instance of a RhinoManager using a context file that you pass to it.

async createRhinoManager(){
this._rhinoManager = await RhinoManager.create(
} catch (err) {
// handle error

NOTE: the call is asynchronous and therefore should be called in an async block with a try/catch.

The inferenceCallback parameter is a function that you want to execute when Rhino makes an inference. The function should accept an object, which will be a JSON representation of the inference.


You can override also the default Rhino model file and/or the inference sensitivity. These optional parameters can be passed in like so:

this._rhinoManager = await RhinoManager.create(

Once you have instantiated a RhinoManager, you can start audio capture and intent inference by calling:

let didStart = await this._rhinoManager.process();

When RhinoManager returns an inference result via the inferenceCallback, it will automatically stop audio capture for you. When you wish to result, call .process() again.

Once your app is done with using RhinoManager, be sure you explicitly release the resources allocated for it:


As you may have noticed, there is no need to deal with audio capture to enable intent inference with RhinoManager. This is because it uses our @picovoice/react-native-voice-processor module to capture frames of audio and automatically pass it to the inference engine.

Low-Level API

Rhino provides low-level access to the inference engine for those who want to incorporate speech-to-intent into a already existing audio processing pipeline.

Rhino is created by passing a context file to its static constructor create:

async createRhino(){
this._rhino = await Rhino.create('/path/to/context/file.rhn');
} catch (err) {
// handle error

As you can see, in this case you don't pass in an inference callback as you will be passing in audio frames directly using the process function. The JSON result that is returned from process will have up to four fields:

  • isFinalized - whether Rhino has made an inference
  • isUnderstood - if isFinalized, whether Rhino understood what it heard based on the context
  • intent - if isUnderstood, name of intent that were inferred
  • slots - if isUnderstood, dictionary of slot keys and values that were inferred
let buffer = getAudioFrame();
try {
let result = await this._rhino.process(buffer);
// inference result example:
// {
// isFinalized: true,
// isUnderstood: true,
// intent: 'orderDrink',
// slots: {
// size: 'medium',
// coffeeDrink: 'americano',
// sugarAmount: 'some sugar'
// }
// }
} catch (e) {
// handle error

For process to work correctly, the audio data must be in the audio format required by Picovoice. The required audio format is found by calling .sampleRate to get the required sample rate and .frameLength to get the required frame size. Audio must be single-channel and 16-bit linearly-encoded.

Finally, once you no longer need the inference engine, be sure to explicitly release the resources allocated to Rhino:


Custom Context

You can create custom Rhino context models using Picovoice Console.

Custom Context Integration

To add a custom context to your React Native application you'll need to add the rhn files to your platform projects. Android contexts must be added to ./android/app/src/main/res/raw/, while iOS contexts can be added anywhere under ./ios, but must be included as a bundled resource in your iOS project. Then in your app code, using the react-native-fs package, retrieve the files like so:

const RNFS = require('react-native-fs');
let contextName = 'context';
let contextFilename = contextName;
let contextPath = '';
if (Platform.OS == 'android') {
// for Android, extract resources from APK
contextFilename += '_android.rhn';
contextPath = `${RNFS.DocumentDirectoryPath}/${contextFilename}`;
await RNFS.copyFileRes(contextFilename, contextPath);
} else if (Platform.OS == 'ios') {
contextFilename += '_ios.rhn';
contextPath = `${RNFS.MainBundlePath}/${contextFilename}`;

Non-English Contexts

In order to run inference on non-English contexts you need to use the corresponding model file. The model files for all supported languages are available here.

Issue with this doc? Please let us know.