Kerabie
SDKs

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-install

Quick 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

PropTypeRequiredDescription
widgetKeystring✓Your widget key from Settings
appNamestring✓Human-readable app name shown in dashboard
appVersionstring✓Your app version
userKerUserNoPre-identified user (name, email, userId)
themeKerThemeNoColors, font family, bubble size
openMode'modal' | 'screen'NoHow 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 settingIn the app
Trigger Page loadShown about 1.5 seconds after a screen appears (each time the screen prop changes).
Trigger Time on pageShown after N seconds in the app.
Trigger Scroll depth, Exit intentWebsite-only. These campaigns are not shown in apps.
On pagesMatched against the screen prop (for example Expo Router's usePathname()). Without the prop, only campaigns for every screen show.
AudienceNew / 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.
FrequencyRemembered on the device: once per visitor, once per day, or once per app launch.
Button Open chat / Open a linkOpens the chat / the link in the browser.
Button Open Knowledge BaseCalls 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-webrtc

Add 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.phaseMeaning
startingAsking Kerabie to start the call
waitingEvery agent is busy; state.queuePosition is the place in line
ringingFree agents are being rung
connectedAnswered by a person or the AI (state.handler)
endedOver; 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' },
  }}
/>
OptionDescription
nameThe agent's name on the button and the call screen. Defaults to Kerabie Agent.
getUserTokenReturns 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.
actionsThings 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>.
uiYour 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-recognition and a development build (not Expo Go). Install it with npx expo install expo-speech-recognition, add its config plugin, and give the microphone and speech recognition permission reasons (NSMicrophoneUsageDescription and NSSpeechRecognitionUsageDescription on 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 (state is unsupported) unless you pass onDeviceOnly: 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 aliases if 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.
  • state tells you why it is not listening: off, asking (permission), listening, denied or unsupported.

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:

  1. Registers Android notification channels (kerabie_messages, kerabie_visitor, kerabie_system)
  2. Requests permission from the user
  3. Gets the Expo push token
  4. 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

ModeBehavior
modalA React Native Modal over your app. The default, works with any navigation setup
sheetA bottom sheet. Needs @gorhom/bottom-sheet, react-native-reanimated and react-native-gesture-handler
pushYour 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

typeUse case
productE-commerce: user asking about an item
orderOrder inquiry or return
transactionFintech: failed/disputed payment
rideRide-sharing: trip issue
errandDelivery/logistics
bookingAppointment or reservation
customAny 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.