React Native

Add Kustomer Chat to a React Native app with @kustomer/chat-react-native. Installation for iOS and Android, configure, opening the chat UI, events and hooks, identity, push, and the platform differences to know about.

@kustomer/chat-react-native wraps the native iOS and Android SDKs, so your app gets the native chat UI on each platform from one JavaScript API.

Version
Package@kustomer/chat-react-native 6.3.6
Native SDKs insideiOS 8.3.0, Android 4.6.2
Built and tested withReact Native 0.77, React 18, New Architecture with Hermes
iOS15.0+ (15.1+ on React Native 0.77)
AndroidminSdk 24, compileSdk 35, Kotlin 2.2+
ExpoNot in Expo Go. Use a development build with native changes.

Install

  1. Add the package

    Shell
    npm install @kustomer/chat-react-native

    For push notifications, also install @react-native-firebase/app and @react-native-firebase/messaging.

  2. iOS

    Set the platform in your Podfile and install pods:

    ios/Podfile
    platform :ios, '15.1'
    Shell
    cd ios && pod install

    Add usage descriptions for attachments to Info.plist: NSCameraUsageDescription, NSPhotoLibraryUsageDescription, NSPhotoLibraryAddUsageDescription and NSMicrophoneUsageDescription.

  3. Android

    The Android SDK needs Kotlin 2.2 or later and, on minSdk 24 and 25, core library desugaring:

    android/build.gradle
    buildscript {
      ext {
        kotlinVersion = "2.2.21"
      }
    }
    android/app/build.gradle
    android {
      compileOptions {
        coreLibraryDesugaringEnabled true
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
      }
    }
    dependencies {
      coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
    }

    The build stops with a clear error if kotlinVersion is older than 2.2.0 or isn't a full MAJOR.MINOR.PATCH version.

  4. Configure

    App.tsx
    import { useEffect } from 'react'
    import KustomerChat from '@kustomer/chat-react-native'
    
    export default function App() {
      useEffect(() => {
        KustomerChat.configure(KUSTOMER_CHAT_KEY, { brandId: 'YOUR_BRAND_ID' }).catch((e) =>
          console.error('Kustomer configure failed', e),
        )
      }, [])
    
      return <Root />
    }

    Use a chat key with only the org.tracking role. Call configure once, early. useIsKustomerConfigured() returns true once it's done.

  5. Open chat

    TSX
    <Button title="Help" onPress={() => KustomerChat.show()} />

React Native 0.77 on Android

These are needed on React Native 0.77 with AGP 8.7, as in Kustomer's example app:

  • In android/gradle.properties, set react.internal.disableJavaVersionAlignment=true.
  • In android/settings.gradle, override R8 to 8.10.21 or later.
  • If the build reports a duplicate META-INF/versions/9/OSGI-INF/MANIFEST.MF, add it to packaging.resources.pickFirsts.

Options

OptionTypePlatformsDescription
brandIdstringBothBrand whose chat settings to use
businessScheduleIdstringBothBusiness schedule for availability
languageKustomerLanguageBothForce the UI language, such as en_us
hideNewConversationButtonbooleanBothHide New conversation
hideKbArticleSharebooleanBothHide sharing on knowledge base articles
showInAppNotificationsbooleanBothBanners for new messages while the app is open. Default false.
enableUrlUnfurlingbooleanBothLink previews. Default true.
enableHistoryStatusFilterbooleanBothStatus filter on the history screen
historyStatusFilterKustomerHistoryStatusFilterBothInitial filter: none, open, closed or requiresAttention
logLevelKustomerLogTypeBotherror, info, debug or all
disablePushbooleanBothTurn off push
skipFCMPushRegistrationbooleanBothRegister push tokens yourself. See Push.
pushEnvironmentPushEnvironmentiOSPushEnvironment.development while testing with debug builds
maxChatAttachmentTotalMBnumberiOSTotal attachment size per message. Default 50.

Open the UI

TypeScript
import KustomerChat, { KustomerDisplayMode } from '@kustomer/chat-react-native'

KustomerChat.show()
KustomerChat.show(KustomerDisplayMode.onlyKnowledgeBase)

const conversation = await KustomerChat.startNewConversation(
  { body: 'Where is my order?', direction: 'user' },
  { orderNumberStr: '4417' },
)

await KustomerChat.openConversation('6716a3a9c4e5f60012ab34c1')
KustomerChat.showKbArticle('ARTICLE_ID')
await KustomerChat.close()

Don't await show() or the showKb* methods: their promises don't resolve consistently across platforms.

KustomerDisplayModeiOSAndroid
default, chatHistoryYesYes
knowledgeBaseHomeYesYes
onlyChat, onlyKnowledgeBaseYesYes
newChat, activeChat, knowledgeBaseYesFalls back to default

On Android, chat opens as a separate Activity, so your app goes to the background and JavaScript timers pause while it's open.

Other methods on KustomerChat

MethodReturns
getUnreadCount()Promise<number>
getOpenConversationCount()Promise<number>: conversations not ended, with a message in the last 30 days
isChatAvailable()Promise<boolean>
isVisible()Promise<boolean>
openChatAssistant(assistantId, startDialog?, initialMessages?, customDescribe?)Opens chat with an assistant. Android ignores startDialog.
handoff(params)Imports a conversation that started elsewhere. Same rules as the web SDK.

To create a conversation without opening the UI, use KustomerChatProvider.createConversation:

TypeScript
import { KustomerChatProvider } from '@kustomer/chat-react-native'

const { conversation } = await KustomerChatProvider.createConversation({
  firstMessage: 'I need help with my order',
  title: 'Order 4417',
  customDescribe: { orderNumberStr: '4417' },
})

Events

TSX
import { useCallback, useState } from 'react'
import { useKustomerEvent } from '@kustomer/chat-react-native'

function UnreadBadge() {
  const [count, setCount] = useState(0)
  const onTotal = useCallback(({ count }: { count: number }) => setCount(count), [])
  useKustomerEvent('onUnreadTotalChange', onTotal)
  return count ? <Badge value={count} /> : null
}

useKustomerEvent re-subscribes when the callback changes, so wrap it in useCallback. Outside components, use KustomerEventEmitter.addListener(event, cb), which returns a subscription with remove(). Subscribe after configure resolves.

EventPayload
onChatMessageReceivedThe message
onUnreadTotalChange{ count }
onUnreadCountChange{ conversationId, count }
onAgentIsTyping{ conversationId, typingIndicator }
onAgentJoinedThe agent
onConversationCreated, onConversationEnded, onConversationResumed, onConversationDeletedThe conversation
onConversationMerged{ source, target }
onSatisfactionEventReceivedThe CSAT survey
onOpenConversationCountChanged{ count }
onSessionOpened, onSessionCustomAttributesUpdatedThe conversation

Payloads differ slightly between platforms for onAgentJoined, onAssistantEnded and onSatisfactionEventReceived; read fields defensively.

Identity

TypeScript
const signedIn = await KustomerChat.isLoggedIn('email', user.email)
if (!signedIn) await KustomerChat.logIn(jwtFromYourServer)

await KustomerChat.describeCustomer(
  { sharedPhones: ['+15555550123'] },
  { loyaltyTierStr: 'gold' },
)

// on sign-out
await KustomerChat.logOut()
MethodNotes
logIn(jwt)Await it before calling show()
isLoggedIn('email' | 'userId', id)Checks against a specific user
logOutThenLogIn(jwt)Switch users in one call
logOut()Clears chat from the device and deregisters push
describeCustomer(attributes, customAttributes)sharedEmails, sharedPhones and social handles, plus custom attributes
describeConversation(conversationId, attributes)Custom attributes on a conversation
useIsKustomerLoggedIn(idType, id)Hook that polls login state

See Customer identity for generating the JWT.

Push notifications

Android uses Firebase Cloud Messaging and is automatic: with @react-native-firebase/messaging installed, configure registers the FCM token, re-registers on refresh, and handles foreground messages. To do it yourself, set skipFCMPushRegistration: true:

TypeScript
import messaging from '@react-native-firebase/messaging'

messaging().getToken().then(KustomerChat.setPushToken)
messaging().onTokenRefresh(KustomerChat.setPushToken)
messaging().onMessage((message) => {
  if (KustomerChat.isKustomerNotification(message)) KustomerChat.onRemoteMessage(message)
})

setPushToken and onRemoteMessage are Android only.

iOS uses APNs and needs native code in your AppDelegate, the same as the native SDK. The automatic FCM registration only works on Android, so set skipFCMPushRegistration: Platform.OS === 'ios'. See Push notifications.

Troubleshooting

SymptomFix
"The package doesn't seem to be linked"Rebuild the native app after installing, and run pod install. Expo Go isn't supported.
Android: Kotlin version error from the Kustomer moduleSet ext.kotlinVersion to 2.2.0 or later, as a full version.
Android: R8 or Java version errors on React Native 0.77Apply the 0.77 changes.
configure rejects with "already configured with different API key" (iOS)configure ran twice with different settings. Call it once.
Install fails with an engine errorThe package declares Node 24+. Upgrade Node, or use a package manager that doesn't enforce engines.