Getting Started
-
Install the package
Terminal window npm i @capgo/capacitor-speech-recognitionTerminal window pnpm add @capgo/capacitor-speech-recognitionTerminal window yarn add @capgo/capacitor-speech-recognitionTerminal window bun add @capgo/capacitor-speech-recognition -
Sync with native projects
Terminal window npx cap syncTerminal window pnpm cap syncTerminal window yarn cap syncTerminal window bunx cap sync -
Configure platform permissions (see below)
Platform Configuration
Section titled âPlatform ConfigurationâAdd the following keys to your appâs Info.plist file:
<key>NSSpeechRecognitionUsageDescription</key><string>We need access to speech recognition to transcribe your voice</string><key>NSMicrophoneUsageDescription</key><string>We need access to your microphone to record audio for transcription</string>Android
Section titled âAndroidâThe plugin automatically adds the required RECORD_AUDIO permission to your AndroidManifest.xml. No additional configuration is needed.
Basic Usage
Section titled âBasic UsageâCheck Availability
Section titled âCheck AvailabilityâBefore using speech recognition, check if itâs available on the device:
import { SpeechRecognition } from '@capgo/capacitor-speech-recognition';
const checkAvailability = async () => { const { available } = await SpeechRecognition.available(); if (!available) { console.warn('Speech recognition is not supported on this device'); return false; } return true;};Request Permissions
Section titled âRequest PermissionsâRequest the necessary permissions before starting recognition:
const requestPermissions = async () => { const { speechRecognition } = await SpeechRecognition.requestPermissions();
if (speechRecognition === 'granted') { console.log('Permission granted'); return true; } else { console.log('Permission denied'); return false; }};Start Recognition
Section titled âStart RecognitionâStart listening for speech with optional configuration:
// Basic usageawait SpeechRecognition.start({ language: 'en-US', maxResults: 3, partialResults: true,});
// With all optionsawait SpeechRecognition.start({ language: 'en-US', maxResults: 5, prompt: 'Speak now...', // Android only popup: false, // Android only partialResults: true, addPunctuation: true, // iOS 16+ only allowForSilence: 2000, // Android only, milliseconds});Listen for Results
Section titled âListen for ResultsâSubscribe to partial results while recognition is active:
const partialListener = await SpeechRecognition.addListener( 'partialResults', (event) => { const transcription = event.matches?.[0]; console.log('Partial result:', transcription); });
// Don't forget to remove the listener when doneawait partialListener.remove();Stop Recognition
Section titled âStop RecognitionâStop listening and clean up resources:
await SpeechRecognition.stop();Complete Example
Section titled âComplete ExampleâHereâs a complete example showing how to use the plugin:
import { SpeechRecognition } from '@capgo/capacitor-speech-recognition';
export class VoiceRecognitionService { private partialListener: any = null; private isListening = false;
async initialize(): Promise<boolean> { // Check availability const { available } = await SpeechRecognition.available(); if (!available) { throw new Error('Speech recognition not available'); }
// Request permissions const { speechRecognition } = await SpeechRecognition.requestPermissions(); if (speechRecognition !== 'granted') { throw new Error('Permission denied'); }
return true; }
async startListening( onPartialResult: (text: string) => void, onFinalResult: (text: string) => void ): Promise<void> { if (this.isListening) { console.warn('Already listening'); return; }
try { // Set up partial results listener this.partialListener = await SpeechRecognition.addListener( 'partialResults', (event) => { const text = event.matches?.[0] || ''; onPartialResult(text); } );
// Start recognition const result = await SpeechRecognition.start({ language: 'en-US', maxResults: 3, partialResults: true, addPunctuation: true, });
this.isListening = true;
// Handle final result if partialResults is false if (result.matches && result.matches.length > 0) { onFinalResult(result.matches[0]); } } catch (error) { console.error('Error starting speech recognition:', error); throw error; } }
async stopListening(): Promise<void> { if (!this.isListening) { return; }
try { await SpeechRecognition.stop();
// Clean up listener if (this.partialListener) { await this.partialListener.remove(); this.partialListener = null; }
this.isListening = false; } catch (error) { console.error('Error stopping speech recognition:', error); throw error; } }
async getSupportedLanguages(): Promise<string[]> { const { languages } = await SpeechRecognition.getSupportedLanguages(); return languages; }
async checkListeningState(): Promise<boolean> { const { listening } = await SpeechRecognition.isListening(); return listening; }}API Reference
Section titled âAPI Referenceâavailable()
Section titled âavailable()âChecks whether the native speech recognition service is usable on the current device.
const result = await SpeechRecognition.available();// Returns: { available: boolean }start(options?)
Section titled âstart(options?)âBegins capturing audio and transcribing speech.
interface SpeechRecognitionStartOptions { language?: string; // Locale identifier (e.g., 'en-US') maxResults?: number; // Maximum number of results (default: 5) prompt?: string; // Android only: Dialog prompt popup?: boolean; // Android only: Show system dialog partialResults?: boolean; // Stream partial results addPunctuation?: boolean; // iOS 16+ only: Add punctuation allowForSilence?: number; // Android only: Silence timeout in ms}
const result = await SpeechRecognition.start(options);// Returns: { matches?: string[] }Stops listening and tears down native resources.
await SpeechRecognition.stop();getSupportedLanguages()
Section titled âgetSupportedLanguages()âGets the locales supported by the underlying recognizer.
Note: Android 13+ devices no longer expose this list; in that case languages will be empty.
const result = await SpeechRecognition.getSupportedLanguages();// Returns: { languages: string[] }isListening()
Section titled âisListening()âReturns whether the plugin is actively listening for speech.
const result = await SpeechRecognition.isListening();// Returns: { listening: boolean }checkPermissions()
Section titled âcheckPermissions()âGets the current permission state.
const result = await SpeechRecognition.checkPermissions();// Returns: { speechRecognition: 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied' }requestPermissions()
Section titled ârequestPermissions()âRequests the microphone + speech recognition permissions.
const result = await SpeechRecognition.requestPermissions();// Returns: { speechRecognition: 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied' }Event Listeners
Section titled âEvent ListenersâpartialResults
Section titled âpartialResultsâListen for partial transcription updates while partialResults is enabled.
const listener = await SpeechRecognition.addListener( 'partialResults', (event: { matches: string[] }) => { console.log('Partial:', event.matches?.[0]); });segmentResults (Android only)
Section titled âsegmentResults (Android only)âListen for segmented recognition results.
const listener = await SpeechRecognition.addListener( 'segmentResults', (event: { matches: string[] }) => { console.log('Segment:', event.matches?.[0]); });endOfSegmentedSession (Android only)
Section titled âendOfSegmentedSession (Android only)âListen for segmented session completion events.
const listener = await SpeechRecognition.addListener( 'endOfSegmentedSession', () => { console.log('Segmented session ended'); });listeningState
Section titled âlisteningStateâListen for changes to the native listening state.
const listener = await SpeechRecognition.addListener( 'listeningState', (event: { status: 'started' | 'stopped' }) => { console.log('Listening state:', event.status); });removeAllListeners()
Section titled âremoveAllListeners()âRemoves all registered listeners.
await SpeechRecognition.removeAllListeners();Best Practices
Section titled âBest Practicesâ-
Always check availability and permissions
const { available } = await SpeechRecognition.available();if (!available) return;const { speechRecognition } = await SpeechRecognition.requestPermissions();if (speechRecognition !== 'granted') return; -
Clean up listeners Always remove listeners when theyâre no longer needed to prevent memory leaks:
await listener.remove();// orawait SpeechRecognition.removeAllListeners(); -
Handle errors gracefully
try {await SpeechRecognition.start({ language: 'en-US' });} catch (error) {console.error('Speech recognition failed:', error);// Show user-friendly error message} -
Provide visual feedback Use the
listeningStateevent to show users when the app is actively listening. -
Test with different accents and languages Speech recognition accuracy varies by language and accent. Test thoroughly with your target audience.
Platform Notes
Section titled âPlatform Notesâ- Requires iOS 10.0+
- Uses native
SFSpeechRecognizer - Supports punctuation on iOS 16+
- Requires both microphone and speech recognition permissions
- Recognition may fail if device language doesnât match requested language
Android
Section titled âAndroidâ- Requires Android 6.0 (API 23)+
- Uses
SpeechRecognizerAPI - Supports segmented sessions with configurable silence detection
- Android 13+ doesnât expose list of supported languages
- Some devices may show system recognition UI
- Limited support via Web Speech API
- Not all browsers support speech recognition
- Requires HTTPS connection
- May have different behavior across browsers
Troubleshooting
Section titled âTroubleshootingâPermission Denied
Section titled âPermission DeniedâIf permissions are denied, guide users to app settings:
const { speechRecognition } = await SpeechRecognition.checkPermissions();if (speechRecognition === 'denied') { // Show instructions to enable permissions in Settings}No Results Returned
Section titled âNo Results Returnedâ- Check microphone is working
- Ensure quiet environment
- Verify language code matches device capabilities
- Check network connection (some platforms require it)
Recognition Stops Unexpectedly
Section titled âRecognition Stops Unexpectedlyâ- Use
isListening()to check state - Listen to
listeningStateevents - Implement auto-restart logic if needed