FigoChat Mobile SDK#
The FigoChat SDK adds a ready-made AI chat screen to React Native, Flutter, native Android and native iOS apps. Users can type, send voice notes and upload files (images are read with OCR). When a live agent takes over, the agent's replies appear in the same chat. The screen uses your brand color, and the conversation runs against your Figo AI assistant.| Platform | Package | Folder in figochatsdk repo |
|---|
| React Native (Expo or bare) | @figolabs/figochat-react-native | react-native/ |
| Flutter (iOS, Android, web*) | figochat | flutter/ |
| Android (Kotlin, Jetpack Compose), Android 8.0+ | :figochat module | android/ |
| iOS (Swift, SwiftUI and UIKit), iOS 16+ | FigoChat Swift package | ios/ |
* Voice notes are not available on Flutter web.
1. Before you start#
1.
An API key. Create one in the Figo AI dashboard under Settings → API Keys. Use a key just for the SDK and give it an expiry date.
2.
An assistant id. This is the id of the assistant your users will chat with.
3.
AI credits. The company must have at least 0.02 credits, or every call returns 401 Insufficient AI credits.
Security: the API key is shipped inside your app, so anyone who unpacks the app can read it. Use a dedicated SDK key, set an expiry, and rotate it if it leaks. For stronger protection, have your backend issue short-lived keys and pass them to initialize after the user signs in.
2. Installation#
React Native#
Bare React Native apps (no Expo) must first run npx install-expo-modules@latest. @react-native-community/netinfo is needed for live agent messages.{
"expo": {
"plugins": [
["expo-audio", { "microphonePermission": "Allow $(PRODUCT_NAME) to record voice messages for chat." }]
]
}
}
Bare iOS: add NSMicrophoneUsageDescription to Info.plist.
Bare Android: add <uses-permission android:name="android.permission.RECORD_AUDIO" /> to AndroidManifest.xml.
Flutter#
iOS (ios/Runner/Info.plist):<key>NSMicrophoneUsageDescription</key>
<string>Record voice messages for chat.</string>
Android (android/app/src/main/AndroidManifest.xml):<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<queries>
<intent><action android:name="android.intent.action.VIEW" /><data android:scheme="https" /></intent>
</queries>
If pod install fails with an error mentioning XCLocalSwiftPackageReference, your CocoaPods is older than your Flutter's Swift Package Manager support. Update CocoaPods, or turn the integration off for the app in pubspec.yaml:Android (native)#
Include the :figochat module from the repo's android/ folder (or publish it to your Maven repository):The module's manifest already declares the internet and microphone permissions and the chat screen. The microphone permission is requested the first time the user taps the mic.iOS (native)#
In Xcode, choose File → Add Package Dependencies…, enter https://bitbucket.org/okpaguu2/figochatsdk.git, and link the FigoChat library to your app target. Then add to Info.plist:<key>NSMicrophoneUsageDescription</key>
<string>Record voice messages for chat.</string>
3. Initialize#
Call initialize once, for example right after the user signs in. Call it again whenever the user or the settings change.React Native#
import { FigoChat } from '@figolabs/figochat-react-native';
FigoChat.initialize({
apiKey: 'YOUR_API_KEY',
assistantId: 'YOUR_ASSISTANT_ID',
fullName: 'Ada Lovelace',
emailAddress: 'ada@example.com',
mobilePhone: '+2348012345678',
primaryColor: '#F97316',
// optional
title: 'Support',
welcomeMessage: 'Hi Ada! How can I help you today?',
});
Flutter#
Android (native)#
iOS (native)#
Parameters#
| Parameter | Type | Required | Default | Description |
|---|
apiKey | string | Yes | – | API key from the dashboard. Sent as Authorization: Bearer <apiKey>. |
assistantId | string | Yes | – | Assistant the user chats with. |
fullName | string | Yes | – | Signed-in user's full name. |
emailAddress | string | Yes | – | Signed-in user's email address. |
mobilePhone | string | Yes | – | Signed-in user's phone number in international format, e.g. +2348012345678. |
primaryColor | string | Yes | – | Brand color as hex (#RGB, #RRGGBB or #RRGGBBAA). Used for the header, the user's messages and the buttons. Text on top is black or white, whichever is easier to read. |
baseUrl (baseURL on iOS) | string / URL | No | https://api.figolabs.ai | API host. |
title | string | No | Chat | Header title. |
welcomeMessage | string | No | – | First assistant message, shown before the user writes anything. |
threadId | string | No | – | Resumes an earlier conversation. Use the value from getThreadId() / threadId. |
maxFiles | number | No | 5 | Most files per message. |
maxFileSizeMB | number | No | 10 | Largest file accepted. |
autoSendVoice | boolean | No | true | true sends the transcribed voice note right away; false puts the text in the input box so the user can edit it first. |
timeoutMs (RN), timeout (Flutter, iOS), timeoutMillis (Android) | number / Duration / TimeInterval | No | 120 s | Request timeout. |
initialize throws a CONFIG error if a required value is empty or primaryColor isn't a hex color.
4. Show the chat screen#
React Native#
import { FigoChatView } from '@figolabs/figochat-react-native';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
<Modal visible={open} animationType="slide" onRequestClose={() => setOpen(false)}>
{/* a Modal is its own native window, so it needs its own SafeAreaProvider */}
<SafeAreaProvider>
<SafeAreaView style={{ flex: 1 }}>
<FigoChatView onClose={() => setOpen(false)} />
</SafeAreaView>
</SafeAreaProvider>
</Modal>
Without the SafeAreaProvider inside the Modal, the header slides under the status bar on iPhones.| Prop | Type | Default | Description |
|---|
onClose | () => void | – | Shows a close button in the header. |
showHeader | boolean | true | Hide the header if your app draws its own. |
placeholder | string | Type a message | Input placeholder. |
enableVoice | boolean | true | Show the microphone button. |
enableAttachments | boolean | true | Show the attach button. |
keyboardVerticalOffset | number | 0 | Extra space above the keyboard on iOS. Rarely needed: the screen already keeps the input just above the keyboard, including inside modals. |
icons | object | – | Replace the built-in icons: send, attach, mic, stop, close, newChat. |
onError | (e: FigoChatError) => void | – | Called for every error the screen shows (for logging). |
style | ViewStyle | – | Container style. |
Flutter#
| Parameter | Type | Default | Description |
|---|
onClose | VoidCallback? | – | Shows a close button in the header. |
showHeader | bool | true | Hide the header if your app draws its own. |
placeholder | String | Type a message | Input placeholder. |
enableVoice | bool | true | Show the microphone button (always off on web). |
enableAttachments | bool | true | Show the attach button. |
onError | void Function(FigoChatException)? | – | Called for every error the screen shows. |
Android (native)#
FigoChatScreen takes the same options as Flutter's FigoChatView (onClose, showHeader, placeholder, enableVoice, enableAttachments, onError), plus modifier.iOS (native)#
FigoChatView takes onClose, showHeader, placeholder, enableVoice, enableAttachments and onError. FigoChatViewController is the UIKit container if you want to push it yourself.What the screen does#
Text: type and send. A typing indicator shows while the assistant replies. Links in replies can be tapped, and **bold** text is shown in bold.
Voice: tap the microphone, speak, then tap stop. While the recording is turned into text the screen shows "Processing your voice message…", then the text is sent as a message (or placed in the input if autoSendVoice is false). Tap Cancel to discard the recording.
Files: tap the paperclip to pick one or more files (on iPhone, native iOS and Flutter offer Photo library or Files). Each file uploads straight away and shows a progress chip. A file that fails is marked in red and can be removed. When the user sends, the files go with the message. If the user sends only files, the message says "Please review the attached file(s)."
Errors: a message that fails shows "Not sent. Tap to retry", with a plain-language reason such as "Chat isn't available right now. Please try again later." Technical details (for example an invalid API key) are never shown to users; see Errors. Keyboard: the input stays just above the keyboard, and tapping the conversation closes the keyboard.
Live agent: when the conversation is handed to a human agent (Tawk.to, Zoho SalesIQ or FreshChat), the agent's replies appear on the left, like assistant replies, as "Agent name says: …". A notice also appears there when the agent leaves.
New conversation: the refresh button in the header starts a new thread.
How live agent messages work#
After the first reply, the screen subscribes to the conversation's realtime channel. It fetches the realtime settings from your API once per session and keeps them encrypted in memory with the SDK's FigoCrypto util (AES-256 with a random per-session key). They're decrypted only at the moment the channel is subscribed. The subscription stops when the chat closes or a new conversation starts.
5. Other SDK calls#
| React Native | Flutter, Android, iOS | Description |
|---|
FigoChat.getThreadId() | FigoChat.threadId | Current thread id. Save it to resume later with initialize({ threadId }). |
FigoChat.resetConversation() | FigoChat.resetConversation() | The next message starts a new thread. |
FigoChat.logout() | FigoChat.logout() | Clears the settings, e.g. when the user signs out. |
FigoChat.isInitialized() | FigoChat.isInitialized | Whether initialize has been called. |
FigoChat.getClient() | FigoChat.client | The API client, for building your own UI. |
new FigoCrypto() | FigoCrypto() | The encrypt/decrypt util, if you want to protect other values in memory: encrypt(text) and decrypt(value). |
friendlyMessage(error, context) | friendlyMessage(error, context) | The user-facing text for an error, as the chat screen shows it. context is chat, voice, recording or upload. |
Building your own UI#
// React Native
const client = FigoChat.getClient();
const { answer, threadId } = await client.sendMessage('Hello', [/* uploaded file urls */]);
const text = await client.transcribe({ uri, name: 'voice.m4a', mimeType: 'audio/mp4' });
const urls = await client.uploadFiles([{ uri, name: 'receipt.jpg', mimeType: 'image/jpeg' }]);
6. Errors#
Every SDK call throws FigoChatError (React Native, iOS) or FigoChatException (Flutter, Android), each with a message and a code.What users see#
The chat screen never shows the technical message to users. It shows plain-language text instead:| Situation | Codes | Message shown in the chat |
|---|
| The chat can't work until you fix something (bad or expired key, no credits, plan limit, bad setup) | 401, 403, 49, CONFIG, NOT_INITIALIZED | Chat isn't available right now. Please try again later. |
| No connection | NETWORK | You seem to be offline. Check your internet connection and try again. |
| Slow response | TIMEOUT | This is taking longer than usual. Please try again. |
| Anything else, when sending a message | other | Your message couldn't be sent. Please try again. |
| Anything else, with a voice message | other | We couldn't process your voice message. Please try again. |
| Anything else, when starting the microphone | other | The microphone couldn't start. Please try again. |
| Anything else, with a file | other | We couldn't upload that file. Please try again. |
The full technical error still reaches onError, so log it there to find out why chat is unavailable. Apps with their own UI can call friendlyMessage(error) to get the same text.Error codes#
code | Meaning | What to do |
|---|
401 | Invalid or expired API key, missing header, or under 0.02 credits. The message gives the reason. | Check the key and the credit balance. |
49 | The company's plan doesn't include this API. | Upgrade the plan. |
99 | The API couldn't complete the request (e.g. a file failed to upload). | Retry. |
TIMEOUT | No response within the timeout. | Retry. |
NETWORK | No connection. | Retry when the device is back online. |
PARSE | The server returned something that isn't JSON. | Check baseUrl. |
CONFIG | Bad initialize parameters. | Fix the parameters. |
NOT_INITIALIZED | An SDK call was made before initialize. | Call initialize first. |
EMPTY | A message with no text and no files. | – |
FILE_READ | The picked file couldn't be read (React Native only). | Pick the file again. |
REALTIME | Live agent messages are unavailable (realtime not configured on the server, or the connection failed). Chat itself still works. | Check the server's realtime settings and the network. |
7. Full examples#
React Native#
import React, { useEffect, useState } from 'react';
import { Button, Modal, View } from 'react-native';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
import { FigoChat, FigoChatView } from '@figolabs/figochat-react-native';
export default function App() {
const [open, setOpen] = useState(false);
useEffect(() => {
FigoChat.initialize({
apiKey: 'YOUR_API_KEY',
assistantId: 'YOUR_ASSISTANT_ID',
fullName: 'Ada Lovelace',
emailAddress: 'ada@example.com',
mobilePhone: '+2348012345678',
primaryColor: '#F97316',
title: 'Support',
welcomeMessage: 'Hi Ada! How can I help you today?',
});
}, []);
return (
<View style={{ flex: 1, justifyContent: 'center' }}>
<Button title="Chat with us" onPress={() => setOpen(true)} />
<Modal visible={open} animationType="slide" onRequestClose={() => setOpen(false)}>
<SafeAreaProvider>
<SafeAreaView style={{ flex: 1 }}>
<FigoChatView onClose={() => setOpen(false)} onError={(e) => console.log('FigoChat', e.code, e.message)} />
</SafeAreaView>
</SafeAreaProvider>
</Modal>
</View>
);
}
Flutter#
Android (native)#
iOS (native, SwiftUI)#
8. Example apps#
The figochatsdk repository has a runnable example for each platform. Without an API key they still open the chat, and messages fail with the friendly "Chat isn't available right now" text, which is useful for checking the UI.| Platform | Folder | Run |
|---|
| React Native (Expo) | react-native/example | Put the key in .env (see .env.example), then npx expo start --ios |
| Flutter | flutter/example | flutter run --dart-define=FIGO_API_KEY=... --dart-define=FIGO_ASSISTANT_ID=... |
| Android | android/sample | ./gradlew :sample:installDebug -PfigoApiKey=... -PfigoAssistantId=... |
| iOS | ios/Example/FigoChatExample.xcodeproj | Open in Xcode, set FIGO_API_KEY and FIGO_ASSISTANT_ID in the scheme's environment variables, and run |
Modified at 2026-11-14 18:30:11