Embed React Native SDK Integration Guide

Overview

The Embed React Native SDK is a powerful voice-enabled AI agent library that provides real-time communication capabilities. This comprehensive guide will walk you through the complete integration process from installation to deployment.

Prerequisites

  • Node.js 18+
  • React Native 0.74 or higher
  • Platform specific:
    • iOS 13+
    • Android API 21+

This SDK requires proper setup of audio permissions and real-time communication dependencies.

Installation

Install the Embed React Native SDK using your preferred package manager:

npm install @revrag-ai/embed-react-native

Peer Dependencies

The SDK requires several peer dependencies to be installed in your project. Install all required dependencies:

# Install peer dependencies
npm install @livekit/react-native @livekit/react-native-webrtc
npm install @react-native-async-storage/async-storage
npm install react-native-gesture-handler react-native-reanimated
npm install react-native-linear-gradient lottie-react-native
npm install react-native-safe-area-context

# For iOS, run pod install
cd ios && pod install && cd ..

Android Configuration

1. Android Manifest Permissions

Add the following permissions to your android/app/src/main/AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Required permissions for Embed SDK -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <!-- Add the following permissions for embed -->
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MICROPHONE" />

    <application
        android:name=".MainApplication"
        android:label="@string/app_name"
        android:icon="@mipmap/ic_launcher"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:allowBackup="false"
        android:theme="@style/AppTheme"
        android:supportsRtl="true"
        android:usesCleartextTraffic="true"
        android:hardwareAccelerated="true"
        >

        <!-- Your activities and other components -->

    </application>
</manifest>

2. Build.gradle Configuration

Add Lottie dependency to your android/app/build.gradle:

dependencies {
    implementation 'com.airbnb.android:lottie:6.0.1'
    // ... other dependencies
}

3. ProGuard Configuration

If you’re using ProGuard, add these rules to your android/app/proguard-rules.pro:

# Embed SDK
-keep class com.revrag.embed.** { *; }
-keep class org.webrtc.** { *; }
-dontwarn org.webrtc.**

# Lottie
-keep class com.airbnb.lottie.** { *; }

iOS Configuration

1. iOS Permissions

CRITICAL: Add the following permissions to your ios/YourAppName/Info.plist. Missing NSMicrophoneUsageDescription will cause the app to crash when accessing the microphone.

<key>NSMicrophoneUsageDescription</key>
<string>This app needs access to microphone for voice communication with AI agent</string>

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
    <key>NSAllowsLocalNetworking</key>
    <true/>
</dict>

2. Pod Installation

After installing peer dependencies, run:

cd ios
pod install
cd ..

3. iOS Build Settings

If you encounter build issues, update your iOS project settings in ios/YourAppName/Info.plist:

  • Enable Bitcode: NO
  • Build Active Architecture Only: YES (for Debug)

Babel Configuration

CRITICAL: React Native Reanimated requires specific Babel configuration. The reanimated plugin must be the last plugin in the plugins array.

Add the React Native Reanimated plugin to your babel.config.js:

module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    // ... other plugins
    'react-native-reanimated/plugin', // ← This MUST be the last plugin
  ],
};

After updating babel.config.js, clean your project cache:

npx react-native start --reset-cache

SDK Initialization

useInitialize Hook

Initialize the SDK at the root level of your application using the useInitialize hook:

import { useInitialize } from '@revrag-ai/embed-react-native';

function App() {
  const { isInitialized, error } = useInitialize({
    apiKey: 'YOUR_API_KEY',
    embedUrl: 'YOUR_EMBED_SERVER_URL',
  });

  if (error) {
    console.error('SDK initialization failed:', error);
  }

  if (!isInitialized) {
    // Show loading screen while initializing
    return <LoadingScreen />;
  }

  // Your app components
  return <YourApp />;
}

Configuration Options

PropertyTypeRequiredDescription
apiKeystringYour Embed API key
embedUrlstringYour Embed server URL

App Setup

1. Wrap App with GestureHandlerRootView

You must wrap your entire app with GestureHandlerRootView for the SDK to work properly.

import React from 'react';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { useInitialize } from '@revrag-ai/embed-react-native';

export default function App() {
  const { isInitialized, error } = useInitialize({
    apiKey: 'your_api_key_here',
    embedUrl: 'https://your-embed-server.com',
  });

  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      {/* Your app components */}
    </GestureHandlerRootView>
  );
}

2. Add EmbedButton Component

Add the floating voice agent button to your screen:

import { EmbedButton } from '@revrag-ai/embed-react-native';

function MyScreen() {
  return (
    <View style={{ flex: 1 }}>
      {/* Your screen content */}
      <EmbedButton />
    </View>
  );
}

Event System

The SDK provides a powerful event system for sending user context and application state to the AI agent.

Available Events

import { EmbedEventKeys } from '@revrag-ai/embed-react-native';

// Available event keys:
EmbedEventKeys.USER_DATA    // 'user_data' - User identity and profile
EmbedEventKeys.SCREEN_STATE // 'state_data' - Application state and context

Event Usage Rules

CRITICAL REQUIREMENTS:

  1. USER_DATA event MUST be sent first before any other events
  2. USER_DATA must include app_user_id for user identification
  3. EmbedButton should only be rendered AFTER USER_DATA event is sent
  4. SCREEN_STATE events can only be sent after USER_DATA is established

Event Methods

import { Embed, EmbedEventKeys } from '@revrag-ai/embed-react-native';

// Send events
await Embed.Event(eventKey, data);  //eventKey == EmbedEventKeys.USER_DATA || EmbedEventKeys.SATE_DATA

// Listen to events (optional)
Embed.on(eventKey, callback); //eventKey == EmbedEventKeys.USER_DATA || EmbedEventKeys.SATE_DATA

Event Flow Example

// Example event flow
try {
  // Step 1: Send user data first (required)
  await Embed.Event(EmbedEventKeys.USER_DATA, {
    app_user_id: 'user123',
    name: 'John Doe',
    email: 'john@example.com',
  });

  // Step 2: Send context data (app_user_id auto-added)
  await Embed.Event(EmbedEventKeys.SCREEN_STATE, {
    screen: 'profile',
    data: { plan: 'premium' },
  });
} catch (error) {
  console.error('Event error:', error);
}

Usage Examples

Complete Integration Example

import React, { useEffect, useState } from 'react';
import { View, StyleSheet, Alert } from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import {
  useInitialize,
  EmbedButton,
  Embed,
  EmbedEventKeys
} from '@revrag-ai/embed-react-native';

export default function App() {
  const [userDataSent, setUserDataSent] = useState(false);

  const { isInitialized, error } = useInitialize({
    apiKey: 'your_api_key_here',
    embedUrl: 'https://your-embed-server.com',
  });

  // Initialize user data when SDK is ready
  useEffect(() => {
    if (isInitialized && !userDataSent) {
      initializeUserData();
    }
  }, [isInitialized, userDataSent]);

  const initializeUserData = async () => {
    try {
      // STEP 1: Send user data first (REQUIRED)
      await Embed.Event(EmbedEventKeys.USER_DATA, {
        app_user_id: 'user123', // Required field
        name: 'John Doe',
        email: 'john@example.com',
        subscription: 'premium',
        joinedDate: '2024-01-15',
      });

      setUserDataSent(true);

      // STEP 2: Send initial screen state
      await Embed.Event(EmbedEventKeys.SCREEN_STATE, {
        screen: 'home',
        timestamp: new Date().toISOString(),
        userActions: [],
      });

      console.log('User data and initial state sent successfully');
    } catch (error) {
      console.error('Failed to initialize user data:', error);
      Alert.alert('Error', 'Failed to initialize voice agent');
    }
  };

  // Send screen state updates
  const updateScreenState = async (screenName, data = {}) => {
    if (!userDataSent) {
      console.warn('Cannot send screen state before user data');
      return;
    }

    try {
      await Embed.Event(EmbedEventKeys.SCREEN_STATE, {
        screen: screenName,
        timestamp: new Date().toISOString(),
        ...data,
      });
    } catch (error) {
      console.error('Failed to update screen state:', error);
    }
  };

  // Handle initialization errors
  if (error) {
    console.error('SDK initialization failed:', error);
    return (
      <View style={styles.errorContainer}>
        <Text>Failed to initialize voice agent</Text>
      </View>
    );
  }

  // Show loading while initializing
  if (!isInitialized) {
    return (
      <View style={styles.loadingContainer}>
        <Text>Initializing voice agent...</Text>
      </View>
    );
  }

  return (
    <GestureHandlerRootView style={styles.container}>
      <View style={styles.content}>
        {/* Your app content */}
        <YourAppComponents onScreenChange={updateScreenState} />
      </View>

      {/* Only render EmbedButton after user data is sent */}
      {userDataSent && <EmbedButton />}
    </GestureHandlerRootView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  content: {
    flex: 1,
  },
  loadingContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  errorContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});
import { useEffect } from 'react';
import { useNavigation } from '@react-navigation/native';
import { Embed, EmbedEventKeys } from '@revrag-ai/embed-react-native';

function NavigationListener() {
  const navigation = useNavigation();

  useEffect(() => {
    const unsubscribe = navigation.addListener('state', (e) => {
      const routeName = e.data.state.routes[e.data.state.index].name;

      // Send screen state when navigation changes
      Embed.Event(EmbedEventKeys.SCREEN_STATE, {
        screen: routeName,
        timestamp: new Date().toISOString(),
        navigationStack: e.data.state.routes.map(route => route.name),
      }).catch(console.error);
    });

    return unsubscribe;
  }, [navigation]);

  return null;
}

Troubleshooting

Common Issues

Best Practices

Event Optimization:

  • Debounce frequent events to avoid overwhelming the API
  • Batch related data in single events
  • Handle offline scenarios with retry logic
  • Store events locally when network is unavailable

Initialization Strategy:

  • Show loading states during SDK initialization
  • Handle initialization errors gracefully
  • Send USER_DATA as early as possible in the app lifecycle
  • Only render EmbedButton after successful initialization

Network & Security:

  • Use HTTPS endpoints in production
  • Test API connectivity during development
  • Handle network failures gracefully
  • Never bypass security requirements in production

Support

For additional help:


Last Updated: June 2025