React Native SDK
Add Kerabie live chat to your iOS or Android app.
The react-native-kerabie-helpdesk package adds a fully customizable chat UI to any React Native app (Expo managed or bare workflow).
Install
# Expo
npx expo install react-native-kerabie-helpdesk socket.io-client @react-native-async-storage/async-storage
# Bare React Native
npm install react-native-kerabie-helpdesk socket.io-client @react-native-async-storage/async-storage
npx pod-installQuick start
Wrap your app in KerAbieProvider. Place it below your gesture/safe-area providers:
import { KerAbieProvider, KerAbieFloatingButton } from 'react-native-kerabie-helpdesk';
export default function App() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<SafeAreaProvider>
<KerAbieProvider
widgetKey="wk_yourorg_123"
appName="My App"
appVersion="1.0.0"
user={{ name: 'Jane', email: 'jane@example.com' }}
theme={{ primaryColor: '#6d28d9' }}
>
<YourNavigator />
<KerAbieFloatingButton />
</KerAbieProvider>
</SafeAreaProvider>
</GestureHandlerRootView>
);
}Provider props
| Prop | Type | Required | Description |
|---|---|---|---|
widgetKey | string | ✓ | Your widget key from Settings |
appName | string | ✓ | Human-readable app name shown in dashboard |
appVersion | string | ✓ | Your app version |
user | KerUser | No | Pre-identified user (name, email, userId) |
theme | KerTheme | No | Colors, font family, bubble size |
openMode | 'modal' | 'screen' | No | How chat opens (default: modal) |
appName and appVersion are shown to agents in the conversation, so they immediately know which app and version the user is on. Critical for bug reports and version-specific support.
Hooks
import { useKerAbieContext } from 'react-native-kerabie-helpdesk';
const { open, close, toggle, sendMessage, unreadCount, isConnected } = useKerAbieContext();
// Open chat
<TouchableOpacity onPress={open}>
<Text>Chat with us</Text>
{unreadCount > 0 && <Badge count={unreadCount} />}
</TouchableOpacity>Campaigns
Proactive messages you create in the dashboard (Campaigns) also appear in your app, above the launcher, with their button. The provider loads your live campaigns once per app launch; there is nothing to add to your code beyond the optional props below.
| Dashboard setting | In the app |
|---|---|
| Trigger Page load | Shown about 1.5 seconds after a screen appears (each time the screen prop changes). |
| Trigger Time on page | Shown after N seconds in the app. |
| Trigger Scroll depth, Exit intent | Website-only. These campaigns are not shown in apps. |
| On pages | Matched against the screen prop (for example Expo Router's usePathname()). Without the prop, only campaigns for every screen show. |
| Audience | New / returning means the first / a later app launch on this device; "hasn't chatted" checks this device's conversations; country is decided by the server from the device's IP. |
| Frequency | Remembered on the device: once per visitor, once per day, or once per app launch. |
| Button Open chat / Open a link | Opens the chat / the link in the browser. |
| Button Open Knowledge Base | Calls your onOpenKnowledgeBase (the chat has no built-in Knowledge Base screen); opens the chat if you don't pass it. |
import { usePathname, router } from 'expo-router';
<KerAbieProvider
widgetKey="wk_yourorg_xxx"
screen={usePathname()}
onOpenKnowledgeBase={() => router.push('/help')}
>Campaign results (shown, opened, clicked, replied) are counted in the dashboard like they are for the website widget. Nothing pops up while the chat is open.
Calls
Customers can call your team from the app: voice, and video if you turn it on. This part is optional. Chat, tickets and notifications work without it, including in Expo Go.
Calls need a development build, because they use native WebRTC code. They do not run in Expo Go. If you do not install the call packages, nothing changes in your app.
Turn calls on in the dashboard under Settings, Calls. Your plan decides how many call minutes you get each month. Calls the AI voice agent answers are counted separately.
Install
npx expo install livekit-client @livekit/react-native @livekit/react-native-expo-plugin @livekit/react-native-webrtc @config-plugins/react-native-webrtcAdd the plugins to app.json, then make a new development build:
{
"expo": {
"plugins": ["@livekit/react-native-expo-plugin", "@config-plugins/react-native-webrtc"]
}
}The app must be allowed to use the microphone, and the camera if you use video: RECORD_AUDIO and CAMERA on Android, and a reason for NSMicrophoneUsageDescription and NSCameraUsageDescription on iOS.
Add the button
Calls come from a separate entry point, so the main package never loads the call libraries.
import { KerAbieCallButton } from 'react-native-kerabie-helpdesk/calls'
<KerAbieCallButton label="Call us" />
<KerAbieCallButton label="Video call" video />To put call buttons in the chat header itself (a phone, and a camera when video is on), pass the icon variant to the provider. It is a prop, so the main package still never loads the call libraries:
<KerAbieProvider widgetKey="..." callAction={<KerAbieCallButton variant="icon" />}>The button renders nothing when calls are off or the plan has no minutes left. It opens a call screen with the queue position, ringing, the call (mute, camera, end) and how it ended.
For your own design, use useKerAbieCall() for the state and KerAbieCallModal for the screen:
import { useKerAbieCall, KerAbieCallModal } from 'react-native-kerabie-helpdesk/calls'
const call = useKerAbieCall()
// call.available, call.state.phase, call.start(), call.hangUp(), call.dismiss()
<KerAbieCallModal call={call} />state.phase | Meaning |
|---|---|
starting | Asking Kerabie to start the call |
waiting | Every agent is busy; state.queuePosition is the place in line |
ringing | Free agents are being rung |
connected | Answered by a person or the AI (state.handler) |
ended | Over; state.endReason says why |
If you ask customers for their details before a chat (the pre-chat form in the dashboard), the call asks the same questions first, once. Pass user to KerAbieProvider, or call setUser after login, and a customer you have identified is never asked. On a video call the customer sees the agent, with their own camera as a small picture in the corner.
A call goes to every free agent at once and the first to answer wins. When nobody is free, the AI voice agent answers if you turned it on. Otherwise the customer waits in the queue, and the call is marked missed after two minutes.
AI agent
An agent inside your app, in the chat and by voice, that uses your tools as the signed-in customer, shows screens instead of reading lists, and hands over to your team with a summary. Read AI agent for your app first for how tools, secure routes and screens work.
The chat agent runs everywhere, including Expo Go. The voice agent needs a development build and does not run in Expo Go, like calls. Do not import react-native-kerabie-helpdesk/calls in an Expo Go build.
In the chat
Pass agent to the provider and the chat window can use your tools, show your screens and run your app actions, typed instead of spoken:
<KerAbieProvider
widgetKey="wk_yourorg_123"
agent={{
getUserToken: async () => auth.currentToken(),
ui: { pick_saved_address: async ({ purpose }) => pickAddress(purpose) },
actions: { add_to_cart: { description: 'Adds an item to the cart in the app', run: async () => 'Added' } },
}}
>Voice
import { KerAbieAgentButton } from 'react-native-kerabie-helpdesk/calls'
<KerAbieAgentButton
name="Kerabie Agent"
getUserToken={async () => auth.currentToken()}
ui={{
pick_saved_address: async ({ purpose }) => pickAddress(purpose),
pick_schedule: async ({ purpose, earliest }) => pickDateTime(),
open_screen: async ({ screen }) => { navigation.navigate(screen); return 'opened' },
}}
/>| Option | Description |
|---|---|
name | The agent's name on the button and the call screen. Defaults to Kerabie Agent. |
getUserToken | Returns the signed-in customer's token (the one your own API accepts), or nothing when nobody is signed in. Sent to your server in X-Kerabie-User-Token for secure tools. |
actions | Things your app does for the agent on the device (add to the app's own cart, start its checkout). Each is { description, parameters?, run } and becomes a tool named action_<name>. |
ui | Your screens: pick_saved_address, pick_schedule, open_screen, and optionally your own versions of show_items, confirm_action, request_address_input. Each resolves with the customer's answer, or throws if they close it. |
Wake by saying its name
Customers can start the voice agent by saying its name: "Kerabie Agent", "hi Kerabie Agent", "hello Ted". The name alone is enough; "hi", "hey" and "hello" before it are accepted. Small mishearings of a longer name are forgiven, and the name is whatever you call your agent, so it works for any name.
import { useKerAbieAgent } from 'react-native-kerabie-helpdesk/calls'
import { useKerAbieWakeWord } from 'react-native-kerabie-helpdesk/wake'
const agent = useKerAbieAgent({ getUserToken, ui, actions })
useKerAbieWakeWord({
name: 'Ted', // the agent's name
enabled: agent.call.state.phase === 'idle', // never listen during a call
onWake: agent.start,
})What to know before you turn it on:
- It needs
expo-speech-recognitionand a development build (not Expo Go). Install it withnpx expo install expo-speech-recognition, add its config plugin, and give the microphone and speech recognition permission reasons (NSMicrophoneUsageDescriptionandNSSpeechRecognitionUsageDescriptionon iOS). The customer is asked the first time. - It listens only while your app is open on screen, never in the background. iOS does not allow background listening for this, and Android would need a permanent notification.
- By default it uses recognition that runs on the phone, so no audio leaves it. A phone that cannot do that does not listen (
stateisunsupported) unless you passonDeviceOnly: false, which lets the phone's speech service process the audio. - The microphone is on while it listens, so the system shows its microphone indicator and the battery is used. Offer it as a setting the customer turns on, not as the default.
- It can mishear, and it can wake when someone says the name in a conversation. Pass the spellings your engine produces in
aliasesif it keeps mishearing the name. - Starting the call takes a second or two, so the agent greets the customer first. It stops listening the moment the name is heard, because the call needs the microphone.
statetells you why it is not listening:off,asking(permission),listening,deniedorunsupported.
A list, a confirmation and an address box are built in. For your own design use useKerAbieAgent({ getUserToken, ui }) and render <KerAbieCallModal call={agent.call} inRoom={agent.inRoom} />. It needs livekit-client 2.23 or newer.
Push notifications
Kerabie keeps one push token per visitor session, so your app uses one push service. Expo is built in. For Firebase or another service, pass an adapter in notifications.adapter that can ask for permission, return the token with its provider (expo or fcm), and report taps. Without one the SDK uses Expo.
Using Firebase (fcm)? Connect your Firebase project once in the dashboard under Settings, Integrations, App push, so Kerabie can send to your app's customers. Expo push needs nothing there.
Android: register notification channels first
On Android 8+ (API 26+), push notifications require a registered channel. Without one, notifications are silently dropped. Call NotificationService.setup() before the provider renders:
import { NotificationService } from 'react-native-kerabie-helpdesk';
// In App.tsx / _layout.tsx, before KerAbieProvider:
useEffect(() => {
NotificationService.setup({
projectId: 'your-expo-project-id', // from app.json / expo.dev
onTokenReceived: (token) => console.log('Push token:', token),
});
}, []);This single call:
- Registers Android notification channels (
kerabie_messages,kerabie_visitor,kerabie_system) - Requests permission from the user
- Gets the Expo push token
- Registers the token with the Kerabie API automatically
Custom channels
Override the default channels to match your app's branding:
await NotificationService.setup({
channels: [
{
channelId: 'my_app_chat',
name: 'Support Chat',
importance: 'high',
sound: 'default',
enableVibrate: true,
},
],
});app.json: required Android config
Make sure your app.json includes:
{
"expo": {
"android": {
"permissions": ["NOTIFICATIONS"],
"googleServicesFile": "./google-services.json"
},
"plugins": ["expo-notifications"]
}
}Foreground notifications
import { useKerAbieNotifications } from 'react-native-kerabie-helpdesk';
function AppInner() {
const { requestNotificationPermission } = useKerAbieNotifications();
useEffect(() => {
requestNotificationPermission();
}, []);
return <YourApp />;
}Open modes
| Mode | Behavior |
|---|---|
modal | A React Native Modal over your app. The default, works with any navigation setup |
sheet | A bottom sheet. Needs @gorhom/bottom-sheet, react-native-reanimated and react-native-gesture-handler |
push | Your app's own navigator shows the chat. The SDK calls onNavigate and you open the screen |
<KerAbieProvider openMode="modal" widgetKey="...">Using your own navigator (push)
The SDK never touches your navigator, so one hook works with Expo Router and React Navigation. From Expo SDK 56, Expo Router no longer allows @react-navigation/* imports in app code, which is why the SDK asks you to navigate instead of taking a navigation ref.
import { router } from 'expo-router';
<KerAbieProvider
widgetKey="wk_xxx"
openMode="push"
onNavigate={(route) =>
router.push(route.type === 'conversation' ? `/chat/${route.conversationId}` : '/chat')
}
>You define the /chat route and render KerAbieChatScreen in it. Without onNavigate, the chat opens inline.
Contextual chat: open with context
Use openWithContext to open the chat widget with a pre-loaded context payload. The agent sees the context (order details, product info, transaction data) immediately when they open the conversation.
This is the recommended pattern for any app where users need help about a specific item.
Open when a product is clicked
import { useKerAbieContext } from 'react-native-kerabie-helpdesk';
function ProductCard({ product }) {
const { openWithContext } = useKerAbieContext();
return (
<Pressable onPress={() => openWithContext({
type: 'product',
id: String(product.id),
title: product.name,
data: { price: product.price, category: product.category },
})}>
<Text>{product.name}</Text>
</Pressable>
);
}Open for an order inquiry
const { openWithContext } = useKerAbieContext();
// In an order detail screen:
<Button onPress={() => openWithContext({
type: 'order',
id: order.reference,
title: `Order ${order.reference}`,
data: {
status: order.status,
total: order.amount,
placedAt: order.createdAt,
},
})}>
Get help with this order
</Button>Open for a fintech transaction
<Button onPress={() => openWithContext({
type: 'transaction',
id: txn.id,
title: `₦${txn.amount} Transfer`,
data: { status: txn.status, recipient: txn.recipientName, narration: txn.narration },
})}>
Report this transaction
</Button>Open for a ride
<Button onPress={() => openWithContext({
type: 'ride',
id: ride.id,
title: `Trip to ${ride.destination}`,
data: { driver: ride.driverName, fare: ride.fare, status: ride.status },
})}>
Get help with this trip
</Button>Context type reference
type | Use case |
|---|---|
product | E-commerce: user asking about an item |
order | Order inquiry or return |
transaction | Fintech: failed/disputed payment |
ride | Ride-sharing: trip issue |
errand | Delivery/logistics |
booking | Appointment or reservation |
custom | Any other context (pass a descriptive title) |
Theming
<KerAbieProvider
widgetKey="..."
theme={{
primaryColor: '#6d28d9',
backgroundColor: '#ffffff',
textColor: '#1e293b',
fontFamily: 'Inter_400Regular',
bubbleSize: 56,
borderRadius: 16,
}}
>Use with an AI assistant
Connect the Kerabie MCP server to Claude, Cursor or another MCP client and it can search these docs, read the React Native SDK types and follow the integration guide while it writes code for you. No API key is needed for that.