Skip to content
SDK

React Native SDK

Official React Native client library for Nur's Voice AI platform. Build native iOS and Android voice apps with React.

Installation

Requires React Native 0.70+ and React 18+. Install via npm or yarn:

1npm install @nur/react-native

For iOS, run pod install:

1cd ios && pod install && cd ..

Quick Start

Create a client and generate your first speech with hooks:

1import React from 'react';
2import { View, Button, Text } from 'react-native';
3import { NurProvider, useNur } from '@nur/react-native';
4
5function VoiceApp() {
6 const { tts } = useNur();
7 const [status, setStatus] = React.useState('');
8
9 const generateSpeech = async () => {
10 try {
11 setStatus('Generating...');
12
13 // Generate speech from text
14 const audio = await tts.generate({
15 text: 'Hello from React Native! This is Nur\'s voice AI.',
16 voiceId: 'rachel_v2',
17 language: 'en',
18 });
19
20 // Audio plays automatically on mobile
21 setStatus(`Generated ${audio.duration.toFixed(2)}s of audio`);
22 } catch (error) {
23 setStatus(`Error: ${error.message}`);
24 }
25 };
26
27 return (
28 <View style={{ padding: 20 }}>
29 <Button title="Generate Speech" onPress={generateSpeech} />
30 <Text>{status}</Text>
31 </View>
32 );
33}
34
35export default function App() {
36 return (
37 <NurProvider apiKey="nur_your_api_key_here">
38 <VoiceApp />
39 </NurProvider>
40 );
41}

Authentication

Configure your API key via the NurProvider or environment variables:

1import { NurProvider, NurClient } from '@nur/react-native';
2
3// Option 1: Using NurProvider (recommended for React components)
4export default function App() {
5 return (
6 <NurProvider
7 apiKey="nur_your_api_key_here"
8 config={{
9 baseUrl: 'https://api.nur.ai',
10 timeout: 60000,
11 maxRetries: 3,
12 }}
13 >
14 <YourApp />
15 </NurProvider>
16 );
17}
18
19// Option 2: Direct client instantiation
20const client = new NurClient({
21 apiKey: 'nur_your_api_key_here',
22 baseUrl: 'https://api.nur.ai',
23 timeout: 60000,
24 maxRetries: 3,
25});
26
27// Option 3: Using environment variables (.env)
28// NUR_API_KEY=nur_your_api_key_here
29const client = new NurClient(); // Reads from env

Text to Speech

Generate natural-sounding speech with React hooks and native audio:

1import React from 'react';
2import { View, TextInput, Button, ActivityIndicator } from 'react-native';
3import { useNur } from '@nur/react-native';
4
5function TTSComponent() {
6 const { tts } = useNur();
7 const [text, setText] = React.useState('');
8 const [loading, setLoading] = React.useState(false);
9
10 // Basic generation
11 const generateBasic = async () => {
12 setLoading(true);
13 try {
14 const audio = await tts.generate({
15 text,
16 voiceId: 'rachel_v2',
17 });
18 // Audio plays automatically
19 } finally {
20 setLoading(false);
21 }
22 };
23
24 // With advanced options
25 const generateAdvanced = async () => {
26 const audio = await tts.generate({
27 text,
28 voiceId: 'rachel_v2',
29 language: 'en',
30 speed: 1.0,
31 pitch: 1.0,
32 outputFormat: 'mp3',
33 sampleRate: 24000,
34 enableSSML: true,
35 });
36 };
37
38 // Streaming generation
39 const streamAudio = async () => {
40 const stream = tts.stream({
41 text: 'Streaming long-form content...',
42 voiceId: 'rachel_v2',
43 });
44
45 for await (const chunk of stream) {
46 console.log(`Received ${chunk.length} bytes`);
47 // Chunks play automatically as they arrive
48 }
49 };
50
51 return (
52 <View style={{ padding: 20 }}>
53 <TextInput
54 value={text}
55 onChangeText={setText}
56 placeholder="Enter text to speak..."
57 multiline
58 style={{
59 borderWidth: 1,
60 padding: 10,
61 marginBottom: 10,
62 minHeight: 100
63 }}
64 />
65 <Button
66 title={loading ? 'Generating...' : 'Generate Speech'}
67 onPress={generateBasic}
68 disabled={loading || !text}
69 />
70 {loading && <ActivityIndicator style={{ marginTop: 10 }} />}
71 </View>
72 );
73}
74
75// Using hooks for audio control
76import { useAudio } from '@nur/react-native';
77
78function AudioPlayer() {
79 const { play, pause, stop, isPlaying } = useAudio();
80
81 const handleGenerate = async () => {
82 const audio = await tts.generate({
83 text: 'Hello world',
84 voiceId: 'rachel_v2',
85 autoPlay: false, // Don't play automatically
86 });
87
88 // Manual control
89 await play(audio);
90 };
91
92 return (
93 <View>
94 <Button title={isPlaying ? 'Pause' : 'Play'}
95 onPress={isPlaying ? pause : handleGenerate} />
96 <Button title="Stop" onPress={stop} />
97 </View>
98 );
99}

Speech to Text

High-accuracy transcription with microphone hooks:

1import React from 'react';
2import { View, Button, Text, PermissionsAndroid, Platform } from 'react-native';
3import { useNur, useMicrophone } from '@nur/react-native';
4
5function STTComponent() {
6 const { stt } = useNur();
7 const [transcript, setTranscript] = React.useState('');
8
9 // Request microphone permission
10 const requestPermission = async () => {
11 if (Platform.OS === 'android') {
12 await PermissionsAndroid.request(
13 PermissionsAndroid.PERMISSIONS.RECORD_AUDIO
14 );
15 }
16 };
17
18 React.useEffect(() => {
19 requestPermission();
20 }, []);
21
22 // Real-time transcription with microphone hook
23 const {
24 startRecording,
25 stopRecording,
26 isRecording,
27 transcript: liveTranscript,
28 } = useMicrophone({
29 language: 'en',
30 timestamps: true,
31 onResult: (result) => {
32 if (result.isFinal) {
33 setTranscript((prev) => prev + ' ' + result.text);
34 }
35 },
36 });
37
38 // File transcription
39 const transcribeFile = async () => {
40 const result = await stt.transcribe({
41 file: 'path/to/audio.mp3',
42 language: 'en',
43 speakerDiarization: true,
44 timestamps: true,
45 });
46
47 console.log(result.text);
48
49 // Access segments
50 result.segments.forEach((segment) => {
51 console.log(`[Speaker ${segment.speaker}] ${segment.text}`);
52 console.log(` Time: ${segment.start}s - ${segment.end}s`);
53 });
54 };
55
56 return (
57 <View style={{ padding: 20 }}>
58 <Button
59 title={isRecording ? 'Stop Recording' : 'Start Recording'}
60 onPress={isRecording ? stopRecording : startRecording}
61 color={isRecording ? 'red' : 'blue'}
62 />
63 <Text style={{ marginTop: 20, fontSize: 16 }}>
64 Live: {liveTranscript}
65 </Text>
66 <Text style={{ marginTop: 10, fontSize: 14, color: '#666' }}>
67 Final: {transcript}
68 </Text>
69 <Button
70 title="Transcribe File"
71 onPress={transcribeFile}
72 style={{ marginTop: 20 }}
73 />
74 </View>
75 );
76}

Voice Agents

Build real-time conversational AI with React hooks:

1import React from 'react';
2import { View, Button, FlatList, Text } from 'react-native';
3import { useVoiceAgent } from '@nur/react-native';
4
5function VoiceAgentComponent() {
6 const [messages, setMessages] = React.useState([]);
7
8 const {
9 startSession,
10 endSession,
11 isActive,
12 isSpeaking,
13 } = useVoiceAgent({
14 voiceId: 'rachel_v2',
15 language: 'en',
16 systemPrompt: 'You are a helpful assistant.',
17 temperature: 0.7,
18 maxTokens: 150,
19 onTranscript: (text) => {
20 setMessages((prev) => [...prev, { role: 'user', text }]);
21 },
22 onAgentResponse: (text) => {
23 setMessages((prev) => [...prev, { role: 'agent', text }]);
24 },
25 onError: (error) => {
26 console.error('Voice agent error:', error);
27 },
28 });
29
30 return (
31 <View style={{ flex: 1, padding: 20 }}>
32 <FlatList
33 data={messages}
34 keyExtractor={(item, index) => index.toString()}
35 renderItem={({ item }) => (
36 <View
37 style={{
38 padding: 10,
39 marginVertical: 5,
40 backgroundColor: item.role === 'user' ? '#E3F2FD' : '#F1F8E9',
41 borderRadius: 8,
42 }}
43 >
44 <Text style={{ fontWeight: 'bold' }}>
45 {item.role === 'user' ? 'You' : 'Agent'}
46 </Text>
47 <Text>{item.text}</Text>
48 </View>
49 )}
50 />
51 <View style={{ marginTop: 20 }}>
52 <Button
53 title={isActive ? 'End Conversation' : 'Start Conversation'}
54 onPress={isActive ? endSession : startSession}
55 color={isActive ? 'red' : 'green'}
56 />
57 {isSpeaking && (
58 <Text style={{ textAlign: 'center', marginTop: 10 }}>
59 Agent is speaking...
60 </Text>
61 )}
62 </View>
63 </View>
64 );
65}
66
67// Advanced usage with manual control
68function AdvancedVoiceAgent() {
69 const { voiceAgent } = useNur();
70 const [session, setSession] = React.useState(null);
71
72 const createSession = async () => {
73 const newSession = await voiceAgent.createSession({
74 voiceId: 'rachel_v2',
75 systemPrompt: 'You are a helpful assistant.',
76 });
77
78 setSession(newSession);
79
80 // Handle responses
81 for await (const response of newSession.receive()) {
82 switch (response.type) {
83 case 'transcript':
84 console.log('User:', response.transcript.text);
85 break;
86 case 'agentText':
87 console.log('Agent:', response.agentText);
88 break;
89 case 'audio':
90 // Audio plays automatically
91 break;
92 }
93 }
94 };
95
96 return (
97 <View>
98 <Button
99 title="Create Session"
100 onPress={createSession}
101 />
102 </View>
103 );
104}

Configuration Options

All available client configuration options:

OptionTypeDefaultDescription
apiKeystringNUR_API_KEYYour API key
baseUrlstringhttps://api.nur.aiAPI base URL
timeoutnumber30000Request timeout (ms)
maxRetriesnumber3Maximum retry attempts
retryDelaynumber1000Delay between retries (ms)
autoPlaybooleantrueAuto-play generated audio

Error Handling

The SDK provides typed errors and error boundaries:

1import {
2 NurError,
3 RateLimitError,
4 AuthenticationError,
5 NurErrorBoundary
6} from '@nur/react-native';
7
8// Try-catch error handling
9async function generateSpeech() {
10 try {
11 const audio = await tts.generate({
12 text: 'Hello world',
13 voiceId: 'rachel_v2',
14 });
15 } catch (error) {
16 if (error instanceof RateLimitError) {
17 console.log(`Rate limited. Retry after ${error.retryAfter}s`);
18 setTimeout(() => {
19 // Retry request...
20 }, error.retryAfter * 1000);
21 } else if (error instanceof AuthenticationError) {
22 console.error('Authentication failed: check your API key');
23 } else if (error instanceof NurError) {
24 console.error(`API error [${error.statusCode}]: ${error.message}`);
25 } else {
26 console.error('Unexpected error:', error);
27 }
28 }
29}
30
31// Using error boundary
32function App() {
33 return (
34 <NurErrorBoundary
35 fallback={(error) => (
36 <View style={{ padding: 20 }}>
37 <Text style={{ color: 'red' }}>Error: {error.message}</Text>
38 <Button title="Retry" onPress={() => window.location.reload()} />
39 </View>
40 )}
41 >
42 <YourApp />
43 </NurErrorBoundary>
44 );
45}
46
47// Hook-based error handling
48import { useError } from '@nur/react-native';
49
50function Component() {
51 const { error, clearError } = useError();
52
53 if (error) {
54 return (
55 <View>
56 <Text>Error: {error.message}</Text>
57 <Button title="Dismiss" onPress={clearError} />
58 </View>
59 );
60 }
61
62 return <YourComponent />;
63}

Need Help?