React Native Chatbot UI Kit

View Release Notes →

dialogs_chatbotav_reactnative is a pre-built, themeable chat UI for React Native — drop in EnxChatWidget or EnxChatScreen and get a complete messaging experience backed by your EnableX Dialogs bot. It is not just a chat widget: the same package can upgrade a conversation to a live audio or video call, including a click-to-call handoff into a full native calling UI, so a single install covers both chat and calling.

React Native Chatbot UI Kit v1.0.0  ·  Released August 10, 2026

First release of the React Native Chatbot UI Kit, published on npm. See Release Notes for what's included.

  View on NPM
Setup

Requirements

RequirementVersion
React18.0 or later
React Native0.76 or later (built and tested against 0.84)
iOS (native)15.0 or later
Android (native)minSdkVersion 24 (Android 7.0) or later, compileSdk/targetSdk 35
Node.js20.19.4+ recommended (the sample app targets Node 22)
ArchitectureReact Native New Architecture (Fabric/TurboModules) — mandatory on RN 0.82+

Installation

Install the SDK and its companion libraries

npm install dialogs_chatbotav_reactnative \
  [email protected] \
  react-native-image-picker \
  @react-native-documents/picker \
  @react-native-community/datetimepicker \
  lucide-react-native \
  react-native-markdown-display \
  react-native-svg \
  react-native-video

Pin react-native-webview to exactly 13.16.1. Versions 13.16.2 and later ship a TypeScript typing regression that breaks any code referencing the bare WebView type directly (for example useRef<WebView>()) — see Developer Troubleshooting.

Calling dependencies

Audio calls, video calls, and click-to-call are powered by three native modules working together. All three are mandatory for calling — the feature does not work with only one or two of them, even though react-native-webview is the only one of the three you also install yourself:

PackageRole in calling
react-native-webviewRenders the in-app video overlay on Android and carries chat/call signaling between the bot page and native code.
enx-rtc-react-nativeThe EnableX WebRTC engine — establishes and manages the actual audio/video media session (microphone, camera, network transport).
enx-uikit-react-nativeThe EnableX native calling UI — the full native call screen shown for click-to-call / native UIKit sessions (participant view, mute/camera-switch/disconnect controls).

enx-rtc-react-native and enx-uikit-react-native are installed automatically as dependencies of dialogs_chatbotav_reactnative — you do not add them to your own package.json. They still ship native Kotlin/Swift code, so the Android Gradle step below and a full native rebuild are required regardless.

enx-uikit-react-native additionally declares these as peer dependencies. Install them in your app if you use native (click-to-call / UIKit) video sessions:

npm install react-native-gesture-handler react-native-reanimated \
  @react-navigation/native @react-navigation/stack

Minimum versions: react-native-gesture-handler ≥ 2.24.0, react-native-reanimated ≥ 4.2.0, @react-navigation/native and @react-navigation/stack ≥ 7.0.0.

iOS — CocoaPods

cd ios && pod install && cd ..

Rebuild the app after adding native modules (Xcode: Product › Clean Build Folder, then run).

Android — required Gradle configuration

Add the following block to your app-level android/app/build.gradle, inside the dependencies section (or immediately above it). It excludes a duplicate legacy library pulled in by enx-rtc-react-native that otherwise fails the build with a “Duplicate class” error:

configurations.all {
    exclude group: 'android.arch.lifecycle', module: 'extensions'
}

See Developer Troubleshooting if you hit build errors even after adding this — it covers two additional known issues and their fixes in detail.

Required Permissions MANDATORY

The chat and calling features rely on the OS permissions below. Declare only what your bot actually uses.

Android — AndroidManifest.xml

PermissionNeeded for
INTERNETAlways — chat and media load over the network.
CAMERACamera in video chat and photo/video attachments.
RECORD_AUDIOMicrophone in audio and video calls.
MODIFY_AUDIO_SETTINGSAudio routing during calls.
ACCESS_FINE_LOCATION / ACCESS_COARSE_LOCATIONOnly if the bot uses location, or proactiveLocationPermission is enabled.

Optional hardware flags, so the app can still install on devices without a camera or mic:

<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.microphone" android:required="false" />

Full example manifest block:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-feature android:name="android.hardware.camera" android:required="false" />
    <uses-feature android:name="android.hardware.microphone" android:required="false" />
    <application ...>
        ...
    </application>
</manifest>

Camera and microphone are requested when a video session starts from the chat. Location is requested on first use, or up front if you set proactiveLocationPermission={true} on the widget. If the user denies a permission, only the dependent feature is affected — text chat keeps working. On your main activity, android:windowSoftInputMode="adjustResize" keeps the message field visible above the keyboard.

iOS — Info.plist

KeyNeeded for
NSCameraUsageDescriptionCamera in video chat / capture.
NSMicrophoneUsageDescriptionMicrophone in audio and video calls.
NSLocationWhenInUseUsageDescriptionLocation features inside the chat.
NSPhotoLibraryUsageDescriptionChoosing photos to send in chat.
NSPhotoLibraryAddUsageDescriptionSaving images to the library (if your flow needs it).
<key>NSCameraUsageDescription</key>
<string>Camera is used for video calls with the support agent.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone is used for audio and video calls with the support agent.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Location may be used when the chat requests it.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access lets you attach images in chat.</string>

A missing Info.plist usage-description key crashes the app the moment that capability is used — not a silently-denied prompt. Use HTTPS for your Dialogs host in production; avoid broad “allow all HTTP” App Transport Security exceptions unless your security team requires them.

Credentials

From the EnableX / Dialogs console:

FieldDescription
botIdYour bot identifier.
hostService base URL, e.g. https://dialogs.enablex.io

Optional EnxBotConfig fields rootPath and callingEnabled — use only if your EnableX deployment guide says so.

Integration Steps

  1. Install the SDK and its companion libraries, pinning react-native-webview to exactly 13.16.1 (see Installation above).
  2. Add the required Android manifest permissions and iOS Info.plist usage-description keys (see Required Permissions above).
  3. iOS: run pod install. Android: add the Gradle exclusion for android.arch.lifecycle:extensions.
  4. Render EnxChatWidget or EnxChatScreen with your botId/host — see the Usage Example.
  5. Set showCallingOptions if you want audio/video call buttons in the input bar; implement onAudioCall/onVideoCall to fully own the call UI, or let the widget handle bot-initiated calls automatically.
  6. Do a full clean native rebuild any time the SDK or its native dependencies change version (Android: ./gradlew clean; iOS: pod install + Clean Build Folder).
  7. Test text chat, attachments, and calling on real iOS and Android devices — see Developer Troubleshooting if a native build fails.
Data Types & Enums

Data Types & Enums

Import everything from the package root: import { EnxChatWidget, EnxChatController, /* ... */ } from 'dialogs_chatbotav_reactnative';

EnxBotConfig

Configuration passed to EnxChatController or the config prop of EnxChatWidget / EnxChatScreen.

FieldTypeRequiredDescription
botIdstringYesYour EnableX bot identifier.
hoststringYesDialogs service base URL, e.g. https://dialogs.enablex.io
rootPathstringNoOnly set if your EnableX deployment guide specifies a custom root path.
callingEnabledbooleanNoOnly set if your EnableX deployment guide specifies it.

EnxMessageSender

Enum identifying who sent a message.

MemberValue
User"user"
Bot"bot"

EnxMessageType

MemberValue
Text"text"
Action"action"
Suggestion"suggestion"
Image"image"
File"file"
Video"video"
Typing"typing"
Calendar"calendar"

EnxSuggestionType

MemberValue
Single"single"
Multiple"multiple"

EnxConnectionStatus

Exposed as EnxChatController.status; drives the widget's connection banner.

MemberValueMeaning
Idle"idle"Controller created but initialize() not yet called.
Loading"loading"Initial connection in progress.
Connected"connected"Chat is ready to send/receive.
Disconnected"disconnected"Connection lost.
Reconnecting"reconnecting"Automatic reconnect in progress.
Error"error"Reconnect failed / unrecoverable error.

EnxChoice

FieldTypeDescription
titlestringLabel shown to the user.
valuestringUnderlying value sent to the bot.
isSelectedboolean?Pre-selected state for multi-select choices.

EnxAction

FieldTypeDescription
titlestringButton label.
urlstring?URL to open, if this action is a link.
actionstring?Custom action identifier for your own handling.

EnxMedia

FieldTypeDescription
urlstring?Remote URL of the media.
fileNamestringDisplay file name.
mimeTypestringMIME type, e.g. image/png.
localUristring?Local device URI, for outgoing attachments.
sizenumber?File size in bytes.

EnxLinkCard

Rich link / company preview card rendered instead of a plain URL + file row.

FieldTypeDescription
urlstringDestination URL.
imageUrlstring?Hero image.
titlestring?Card title.
descriptionstring?Card body text.
buttonTitlestring?Call-to-action button label.

EnxMessageDisplayStyle

Type: 'default' | 'systemCentered'. When systemCentered, the message renders as a full-width centered notice chip instead of a side bubble (handover, agent assigned, dropped, etc.).

EnxMessage

The core chat message model. Every message the controller emits or accepts is shaped like this.

FieldTypeDescription
idstring?Message identifier, if provided by the bot.
senderEnxMessageSenderUser or Bot.
typeEnxMessageTypeText, Image, File, Video, Action, Suggestion, Typing, or Calendar.
timestampDateWhen the message was created.
textstring?Body text.
subtitlestring?Secondary line, if any.
displayStyleEnxMessageDisplayStyle?Render as a centered system notice instead of a bubble.
handoverStatusstring?Raw handover state from the bot payload.
mediaEnxMedia?Attached image, file, or video.
linkCardEnxLinkCard?Renders a link preview card instead of a raw URL row.
choicesEnxChoice[]?Selectable suggestion chips.
actionsEnxAction[]?Action buttons.
suggestionTypeEnxSuggestionType?Single or Multiple selection mode for choices.

EnxChatTheme & default themes

FieldTypeDescription
primaryColorstringAccent color (header, buttons, links).
userBubbleColorstringBackground color of the current user's message bubbles.
botBubbleColorstringBackground color of the bot's message bubbles.
backgroundColorstringChat list background.
userAvatarColorstringUser avatar background.
botAvatarColorstringBot avatar background.
useMobileClassicLayoutbooleanSwitches bubble/layout style to match the EnableX mobile web chat.

Two ready-made theme constants are exported:

  • defaultTheme — WhatsApp-style green theme.
  • mobileClassicTheme — matches the EnableX mobile web chat look.
Components

Components

EnxChatWidget

The primary embeddable chat UI. Renders the message list, input bar, connection banner, and (on Android) the hidden WebView bridge or video overlay.

<EnxChatWidget config={{ botId, host }} theme={mobileClassicTheme} />
PropTypeDescription
configEnxBotConfig?Required if controller is not passed. Bot id + host.
controllerEnxChatController?Bring your own controller. If omitted, the widget creates and disposes one automatically.
themePartial<EnxChatTheme>?Overrides merged onto defaultTheme.
showCallingOptionsboolean?Default false. Shows audio/video buttons in the input bar.
onMessageReceived(message: EnxMessage) => voidFired for every inbound message.
onMessageSent(message: EnxMessage) => voidFired for every outbound message.
onError(message: string, type: string) => voidConnection or chat errors.
onBotInfo(info: Record<string, unknown>) => voidBot metadata, when available.
onAudioCall() => voidUser tapped the audio-call button (you own the call UI).
onVideoCall() => voidUser tapped the video-call button (you own the call UI).
onVideoCallRequest(url: string) => voidBot started a video session. The widget also opens its own full-screen presentation unless you fully own the flow.
onVideoCallEnded() => voidBot ended the video session; the widget's own overlay is already closed by this point.
onNativeUIKitRequest(roomToken: string) => voidBot handed off to a native EnableX UIKit room.
proactiveLocationPermissionboolean?Android only, default false. Requests location once on mount instead of waiting for the page to ask.

EnxChatScreen

A full-screen wrapper around EnxChatWidget with a header (title + optional back button).

PropTypeDescription
titlestring?Default "EnX Support". Header title text.
onBack() => voidShows a back button when provided.
configEnxBotConfig?Same as EnxChatWidget.
controllerEnxChatController?Same as EnxChatWidget.
themePartial<EnxChatTheme>?Same as EnxChatWidget.
showCallingOptionsboolean?Same as EnxChatWidget.

ChatList

The scrolling message list used internally by EnxChatWidget. Exported for advanced/custom layouts.

PropTypeDescription
messagesEnxMessage[]Messages to render, oldest first.
isTypingbooleanShows the typing indicator at the bottom.
themeEnxChatThemeFull (non-partial) theme.
onSuggestionTap(titles: string[], type: EnxSuggestionType) => voidUser tapped a suggestion chip.
onActionTap(action: EnxAction) => voidUser tapped an action button.

Accepts a ref of type ChatListHandle, exposing scrollToBottom(animated: boolean): void.

MessageCell

Renders a single message bubble (text, image, video, file, suggestions, actions, or calendar prompt). Exported for custom list implementations.

PropTypeDescription
messageEnxMessageThe message to render.
themeEnxChatThemeFull theme.
onSuggestionTap(titles: string[], type: EnxSuggestionType) => voidOptional.
onActionTap(action: EnxAction) => voidOptional.

InputBar

The bottom text field, attachment picker, and audio/video call buttons.

PropTypeDescription
themeEnxChatThemeFull theme.
enabledbooleanDisables input while the connection is not ready.
showCallingOptionsboolean?Shows the audio/video buttons.
onSendText(text: string) => voidUser submitted text.
onSendFile(payload) => voidUser picked a camera, gallery, or document attachment.
onAudioCall() => voidAudio call button tapped.
onVideoCall() => voidVideo call button tapped.

TypingBubble

Three-dot animated typing indicator.

PropTypeDescription
colorstringDot color.

ChatMarkdown

Renders bot message text with markdown formatting (links, emphasis, lists).

PropTypeDescription
contentstringMarkdown source text.
themeEnxChatThemeFull theme — drives link/accent color.
variantChatMarkdownVariant'body' | 'subtitle' | 'title' | 'linkTitle' | 'linkDesc' | 'button' | 'compact'
containerStyleobject?Extra wrapper style, e.g. horizontal padding.
textColorstring?Overrides the default text/link color (e.g. for choice chips).
EnxChatController

EnxChatController

A framework-agnostic connection and message controller. EnxChatWidget creates one internally if you do not supply your own; you can also own an instance yourself and drive fully custom UI off it.

Constructor

new EnxChatController(config: EnxBotConfig)

Properties (read-only getters)

PropertyTypeDescription
messagesEnxMessage[]All messages in the current conversation, oldest first.
statusEnxConnectionStatusCurrent connection state.
isConnectedbooleanShorthand for status === Connected.
isTypingbooleanTrue while the bot is composing a reply.
botInfoRecord<string, unknown> | undefinedLast bot-info payload received.
conversationIdstring | undefinedCurrent conversation identifier, once assigned.
errorMessagestring | undefinedLast error message, if any.
bridgeEnxWebViewBridgeUnderlying platform bridge (advanced use — see Advanced).

Event callbacks (assign directly)

CallbackSignatureFires when
onMessageReceived(message: EnxMessage) => voidA new message arrives.
onStatusChanged(status: EnxConnectionStatus) => voidConnection status changes.
onError(message: string, type: string) => voidA connection or chat error occurs.
onBotInfoReceived(info: Record<string, unknown>) => voidBot metadata is received.
onVideoCallRequest(url: string) => voidBot sends a video-room URL (audio_video_action: start).
onVideoCallEnd() => voidBot sends audio_video_action: stop.
onNativeUIKitRequest(roomToken: string) => voidBot hands off to a native EnableX UIKit room.

Methods

MethodSignatureDescription
initialize(): Promise<void>Starts the connection. Called automatically by EnxChatWidget.
sendText(text: string): Promise<void>Sends a text message; queued until the connection is ready.
sendSuggestions(titles: string[], type: EnxSuggestionType): Promise<void>Sends one or more selected suggestion chips.
sendChoice(choice: EnxChoice): Promise<void>Convenience wrapper for a single-select choice.
sendMultiChoice(choices: EnxChoice[]): Promise<void>Convenience wrapper for multi-select choices.
sendFile(data: {base64, fileName, mimeType, localUri?, size?}): Promise<void>Sends an attachment; queued until the connection is ready.
resetConversation(): Promise<void>Clears local messages and asks the backend to start a new conversation.
reconnect(): Promise<void>Manually retries the connection.
clearMessages(): voidClears local messages only (no backend call).
dispose(): Promise<void>Tears down the connection and listeners. Call this when you own the controller yourself.
subscribe(listener: () => void): () => voidLow-level subscription used internally by useControllerVersion; returns an unsubscribe function.
Hooks

Hooks

useControllerVersion

function useControllerVersion(controller: EnxChatController): number

Subscribes a component to an EnxChatController and forces a re-render whenever its state changes. Returns an incrementing version number (the value itself is not meaningful — only the fact that it changed).

const version = useControllerVersion(controller);
// component re-renders on every controller.messages / status / isTyping change
Media & Permission Helpers

Media & Permission Helpers

cachedImageSource

function cachedImageSource(uri: string): ImageURISource

Returns an Image source. Remote HTTP(S) URLs get { cache: 'default' } so the platform HTTP cache (honoring Cache-Control from the server) is used; local/data URIs pass through unchanged.

cachedVideoSource

function cachedVideoSource(uri: string): { uri: string; isNetwork?: boolean; shouldCache?: boolean }

Returns a react-native-video source. Remote HTTP(S) URLs get isNetwork: true and shouldCache: true for disk-cached repeat playback; local/content URIs pass through unchanged.

requestCameraAndMicrophoneForMedia

function requestCameraAndMicrophoneForMedia(): Promise<void>

Android only (no-op on iOS, where the system prompt is triggered automatically). Requests CAMERA and RECORD_AUDIO together. Called automatically by EnxChatWidget immediately before a video call starts; denial is silent — the video UI may still open and show its own message.

requestLocationForWebView

function requestLocationForWebView(): Promise<void>

Android only. Requests ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION together. Call this yourself only if you opted into proactiveLocationPermission on the widget; otherwise the WebView requests location natively when the chat page calls navigator.geolocation.

Message Parsing Utilities

Message Parsing Utilities

Lower-level helpers used internally to interpret the raw bridge payload. Most integrations do not need to call these directly — EnxChatController already applies them.

parseBridgeMessage

function parseBridgeMessage(rawData: unknown): EnxMessage[]

Converts a raw bridge payload into zero or more EnxMessage objects.

extractVideoCallUrl

function extractVideoCallUrl(rawData: unknown, botDisplayName?: string): string | undefined

Extracts a video-room URL from a raw bridge payload, if present.

extractVideoCallRoomToken

function extractVideoCallRoomToken(rawData: unknown): string | undefined

Extracts a native EnableX UIKit room token from a raw bridge payload, if present.

isAudioVideoStopPayload

function isAudioVideoStopPayload(rawData: unknown): boolean

True if the payload represents the bot ending an audio/video session (audio_video_action: stop).

Advanced

EnxWebViewBridge

The platform bridge that connects the chat page to native code — a hidden WebView on Android, or the native EnxChatBridge module on iOS. Accessed via controller.bridge. Most apps never need to call this directly; it is documented here for advanced integrations that fully replace the default widget UI.

MemberTypeDescription
usesNativePathbooleanTrue on iOS when the native EnxChatBridge module is available (WKWebView is owned natively, not by React Native).
attachWebViewRef(ref) => voidAndroid only. Attaches the hidden WebView ref so the bridge can inject JavaScript into it.
initializeAfterPageLoad(): voidAndroid only. Call from the WebView's onLoadEnd.
initializeNative(): voidiOS only. Starts the native bridge module.
resetWebViewSession(): voidResets bridge state so the next mount re-initializes cleanly.

formatMultiSuggestionWireText

function formatMultiSuggestionWireText(values: string[]): string

Formats a list of selected multi-suggestion titles into the JSON-array wire text the bot echoes back. Used internally to de-duplicate the echo against the locally-rendered user message.

Usage Example

Usage Example

Simplest — pass config directly

The widget creates and owns its own EnxChatController, and disposes it automatically when it unmounts.

import React from 'react';
import { View } from 'react-native';
import { EnxChatWidget, mobileClassicTheme } from 'dialogs_chatbotav_reactnative';

export function SupportChat() {
  return (
    <View style={{ flex: 1 }}>
      <EnxChatWidget
        config={{
          botId: 'YOUR_BOT_ID',
          host: 'https://dialogs.enablex.io',
        }}
        theme={mobileClassicTheme}
      />
    </View>
  );
}

Own the controller yourself

Use EnxChatController when you need one instance for longer than a single screen, or want to wire extra app logic around it. Call dispose() when you are done — typically in a useEffect cleanup function.

import React, { useEffect, useRef } from 'react';
import { View } from 'react-native';
import { EnxChatController, EnxChatWidget, mobileClassicTheme } from 'dialogs_chatbotav_reactnative';

export function SupportChat() {
  const controllerRef = useRef(
    new EnxChatController({
      botId: 'YOUR_BOT_ID',
      host: 'https://dialogs.enablex.io',
    }),
  );

  useEffect(() => {
    const c = controllerRef.current;
    return () => { void c.dispose(); };
  }, []);

  return (
    <View style={{ flex: 1 }}>
      <EnxChatWidget controller={controllerRef.current} theme={mobileClassicTheme} />
    </View>
  );
}

Full screen with a title bar and back button

import { EnxChatScreen, mobileClassicTheme } from 'dialogs_chatbotav_reactnative';

<EnxChatScreen
  title="Support"
  onBack={() => { /* e.g. navigation.goBack() */ }}
  config={{ botId: 'YOUR_BOT_ID', host: 'https://dialogs.enablex.io' }}
  theme={mobileClassicTheme}
  showCallingOptions
/>

Audio / video calling from the chat bar

Set showCallingOptions to show call actions in the input bar. Implement onAudioCall and onVideoCall to open your own calling flow if you want to override the default behavior. When the bot itself starts a video session, the widget requests camera/microphone permission and opens the call automatically — as a full-screen native view on iOS, or a WebView / native UIKit overlay on Android — unless you handle onVideoCallRequest yourself.

This entire flow — audio calls, video calls, and click-to-call handoff to a native room — runs on top of enx-rtc-react-native (the WebRTC media engine) and enx-uikit-react-native (the native call screen), with react-native-webview carrying signaling and rendering the Android in-app overlay. All three must be present and correctly built for calling to work; see Calling dependencies above, and Developer Troubleshooting if a build fails.

Widget Configuration Reference

The most commonly used EnxChatWidget props — see Components above for the complete, exhaustive reference.

PropDescription
configBot id and host — required if you do not pass controller.
controllerYour own EnxChatController. If omitted, the widget builds one from config.
thememobileClassicTheme, defaultTheme, or your own partial theme object.
showCallingOptionsShow audio/video actions; use with onAudioCall / onVideoCall.
onBotInfoCalled with bot metadata (e.g. display name) when available.
onMessageReceived / onMessageSentFired when messages arrive or are sent.
onErrorConnection or chat errors (message, type).
onVideoCallRequestBot started a video session; handle the URL yourself, or rely on the default full-screen presentation.
onVideoCallEndedBot ended the video session.
proactiveLocationPermissionAndroid only, default false. If true, location is requested when the chat opens instead of waiting until it is needed.
Feature Support

Feature Support (v1.0.0)

FeatureSupportedNotes
Drop-in chat componentsYesEnxChatWidget (embeddable) and EnxChatScreen (full screen with title bar and back button).
Rich message typesYesText, images, video, files, calendar prompts, single/multi-select suggestions, and action buttons.
Markdown renderingYesLinks, emphasis, and lists inside bot messages via ChatMarkdown.
Rich link/company preview cardsYesRendered for URLs shared by the bot via EnxLinkCard.
Typing indicator & system noticesYesDay separators and WhatsApp-style centered system notices (handover, agent assigned, etc.).
ThemingYesTwo ready-made color themes (defaultTheme, mobileClassicTheme) plus full theme overrides.
AttachmentsYesCamera, gallery, or document picker; HTTP-cache-aware image loading and disk-cached video playback for repeat views.
Message de-duplicationYesAutomatic de-duplication of echoed user messages coming back from the bot connection.
Audio/video callingYesCall entry points in the input bar (showCallingOptions, onAudioCall, onVideoCall).
Bot-initiated video sessionsYesFull-screen native video call on iOS, in-app WebView overlay on Android, or a native EnableX UIKit room view for click-to-call handoff.
Automatic call permission requestsYesCamera/microphone permission requested immediately before a call starts.
Framework-agnostic controllerYesEnxChatController can be owned and driven independently of the widget UI.
Full TypeScript typesYesEvery exported component, hook, and data model is fully typed.
UI customization APINoNot available in v1.0 — theming covers colors/layout only, not structural customization.
Reference

Known Issues in Upstream Dependencies

These are pre-existing issues in third-party packages this SDK depends on. They are documented here so you are not blocked by them — fixes for each are covered in Developer Troubleshooting below.

  • Android build fails with a CMake “add_subdirectory” error. On React Native New Architecture builds, enx-uikit-react-native's Android build script incorrectly registers itself for native TurboModule/Fabric codegen even though it ships no codegen spec files. See fix.
  • Android build fails with “Duplicate class” errors. enx-rtc-react-native pulls in the long-abandoned android.arch.lifecycle:extensions library, whose classes duplicate ones already shipped by AndroidX. See fix.
  • TypeScript error referencing react-native-webview's WebView type. Versions 13.16.2+ ship a typing regression that breaks any code referencing the bare WebView type. This SDK pins to 13.16.1. See fix.

Breaking changes: none — this is the first public release.

Developer Troubleshooting

Android build fails: CMake “add_subdirectory” error mentioning enx-uikit-react-native

Cause: enx-uikit-react-native's Android build script registers the module for New Architecture codegen even though it ships no codegen spec files, which breaks the native build:

CMake Error ... add_subdirectory given source
".../node_modules/enx-uikit-react-native/android/build/generated/source/codegen/jni/"
which is not an existing directory.

Fix — install patch-package and remove the offending Gradle block:

  1. Install patch-package as a dev dependency:
    npm install -D patch-package
  2. Open node_modules/enx-uikit-react-native/android/build.gradle and delete this block entirely (do not just comment it out — see the note below):
    if (isNewArchitectureEnabled()) {
      react {
        jsRootDir = file("../src/")
        libraryName = "EnxUikitReactNative"
        codegenJavaPackageName = "com.enxuikitreactnative"
      }
    }

Delete the lines outright rather than commenting them out. React Native's autolinking scans this file with a plain text regex that still matches a commented-out libraryName line.

  1. Generate a patch and wire it to auto-apply on every install:
    npx patch-package enx-uikit-react-native
    # add to package.json scripts:
    "postinstall": "patch-package"
  2. Commit the generated patches/ folder to version control.
  3. Clean the stale autolinking cache and rebuild:
    rm -rf android/build android/app/build android/app/.cxx
    cd android && ./gradlew :app:assembleDebug

Android build fails: “Duplicate class” errors mentioning support-compat

Cause: enx-rtc-react-native depends on the long-abandoned android.arch.lifecycle:extensions library, whose classes duplicate ones already provided by AndroidX.

Fix: add this exclusion to your app-level android/app/build.gradle (see Installation):

configurations.all {
    exclude group: 'android.arch.lifecycle', module: 'extensions'
}

TypeScript error: “No overload matches this call” on <WebView />

Cause: react-native-webview 13.16.2 and later ship a typing regression — the WebView class's generic default became undefined instead of {}, which makes WebViewProps & undefined resolve to never for any code referencing the bare WebView type (for example useRef<WebView>()).

Fix: pin react-native-webview to exactly 13.16.1 in your app's package.json:

"react-native-webview": "13.16.1"

Then reinstall so the exact version resolves in your lockfile:

npm install [email protected] --save-exact

“Install via USB” / INSTALL_FAILED_USER_RESTRICTED on Android

Cause: some OEM Android skins (Xiaomi/MIUI, Samsung, Vivo, Oppo, etc.) block sideloaded installs unless an extra developer option is enabled.

Fix: on the device, enable Settings → Developer options → Install via USB, then retry.

Before You Ship

  • Confirm botId and host point at your production EnableX / Dialogs environment.
  • Match permissions and iOS usage descriptions to what your bot actually uses (see Required Permissions).
  • Test on real Android and iOS devices: text chat, attachments, location, and video if you enable those flows.
  • Prefer HTTPS for your Dialogs host; avoid overly broad ATS or cleartext exceptions in production unless required.
  • Do a full clean native rebuild (Android: ./gradlew clean; iOS: pod install + Clean Build Folder) any time the SDK or its native dependencies change version.