@experiaapp/webchat-react-native
v2.0.7
Published
Experia App live-chat SDK for React Native — drop a real-time support channel (chat, media & video calls) into your app so your customers can reach you with ease.
Readme
@experiaapp/webchat-react-native
A drop-in React Native webchat SDK — real-time chat, media attachments (images, documents, voice notes), and 1:1 video calls — that you embed in your app with a single component. Theming, language (English/Arabic), and behavior are driven by your channel configuration.
- Real-time messaging (text, quick replies, message status, unread tracking)
- Attachments — photos, PDF documents, and recorded voice notes
- In-app video calls (optional)
- Server-driven theming + a customizable launcher
- English / Arabic with full RTL
- Works in Expo and bare React Native
Requirements
- React Native >= 0.85, React >= 19 (New Architecture)
- Node.js >= 20.19.4 to build — the Expo SDK 56 / RN 0.85 minimum (Expo SDK 56 changelog: "React Native 0.85 drops support for Node.js versions before v20.19.4")
- An Expo-managed / dev-client app, or a bare RN app with Expo Modules (see Bare React Native)
- A channel and connection details from your Experia account
Tested against: React Native 0.85.x, Expo SDK 56, React 19.2. The peer ranges (
react-native >=0.85,expo-* >=56,react >=19) leave newer versions open so installs don't break when you bump RN/Expo, but only the matrix above is verified — if you hit an issue on a newer release, pin back to it.
Installation
# the SDK
npm install @experiaapp/webchat-react-native
# required peers (Expo apps)
npx expo install \
react-native-safe-area-context \
react-native-localize \
@react-native-async-storage/async-storageBare React Native (RN CLI)? Do the Bare React Native (RN CLI, no Expo) setup first — it installs the Expo Modules runtime, which is what makes
npx expo installandexpo/metro-configavailable in a bare app.
Optional peers (each enables a feature when installed)
Install the peers for the features you want. A missing peer degrades gracefully at runtime,
but not all in the same way: UI-backed features hide their control (attachment and video-call
buttons, SVG icons), while behavioral ones fall back to a safe no-op — audio routing uses the
default route, screen-capture protection is skipped, and connectivity-aware reconnect is
disabled. Use npx expo install so versions match your Expo SDK:
| Feature | Install |
| --- | --- |
| Photo / document attachments | npx expo install expo-image-picker expo-document-picker expo-file-system |
| Crisp vector icons | npx expo install react-native-svg |
| Connectivity-aware reconnect | npx expo install @react-native-community/netinfo |
| Screen-capture protection (secureScreen) | npx expo install expo-screen-capture |
| Video calls | npx expo install react-native-webrtc react-native-incall-manager (managed apps also need the config plugin — see Expo config plugin) |
Voice notes use
expo-audio, which ships as a direct dependency of the SDK — it's installed automatically; there's nothing to add. (Likeexpo-font/expo-video, its native side still needs the Expo Modules runtime — see Bare React Native.)
Skipping any optional peer? Metro resolves every
require()at build time, and some SDK imports are static (e.g.react-native-webrtcvia the video tile), so omitting a peer fails the bundle (Unable to resolve module …) unless you add the Metro helper. This applies to both bare RN CLI and Expo-managed apps — the only case where you can skip the helper is if you install every optional peer. See Bare React Native (RN CLI, no Expo) for the one-linewithExperiaOptionalDepswrapper (it's a harmless no-op when all peers are present).
Expo config plugin
Add the plugin to your app.json / app.config.js so the required iOS/Android permissions (camera, microphone, photo library) are injected at build time:
{
"expo": {
"plugins": [
"@experiaapp/webchat-react-native",
"@config-plugins/react-native-webrtc" // only if you use video calls
]
}
}@config-plugins/react-native-webrtc is a separate build-time plugin — install it (only if you
use video calls) so expo prebuild can configure WebRTC's native side:
npx expo install @config-plugins/react-native-webrtcVideo calls need a development build — react-native-webrtc is a third-party native module that isn't included in Expo Go. The other features (chat, photo/document attachments via ImagePicker, voice notes via expo-audio, screen-capture protection) use modules that ship in Expo Go, so they run there — but a development build (eas build, or expo prebuild && expo run:ios|run:android) is still recommended for full, production-configured behavior (your app.json permissions and native config only apply to a build, not Expo Go).
Bare React Native (RN CLI, no Expo)
The media, icon, and video features build on Expo Modules + native peers. In a bare React Native CLI app do the following once, in order, then rebuild:
1. Install the Expo Modules runtime. Required so any expo-* module — including the
built-in expo-audio / expo-font / expo-video dependencies — can load its native side.
It also makes npx expo install and expo/metro-config available in your app:
npx install-expo-modules@latest2. Install the required peers (SDK-compatible versions). These are not optional — don't rely on your package manager to add peer dependencies for you:
npx expo install react-native-safe-area-context react-native-localize @react-native-async-storage/async-storage3. Install the peers for the features you want with npx expo install (it picks
SDK-compatible versions — Expo docs).
Install only what you need; skip the rest:
npx expo install expo-image-picker expo-document-picker expo-file-system # photo / document attachments
npx expo install react-native-svg # crisp vector icons
npx expo install @react-native-community/netinfo # connectivity-aware reconnect
npx expo install expo-screen-capture # screen-capture protection
npx expo install react-native-webrtc react-native-incall-manager # video calls4. Extend expo/metro-config and wrap it with the SDK helper. Since Expo Modules are in
use, extend expo/metro-config (not @react-native/metro-config —
Expo docs). The helper is what lets
you safely skip peers in step 3: Metro resolves every require() at build time, so a
missing peer would otherwise fail the bundle with Unable to resolve module …. It stubs any
uninstalled optional peer, and that feature degrades (its UI hides, or it becomes a no-op):
// metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const { withExperiaOptionalDeps } = require("@experiaapp/webchat-react-native/metro");
module.exports = withExperiaOptionalDeps(getDefaultConfig(__dirname));Add the wrapper whenever you skip any peer. If you installed all of them it's a harmless no-op (installed peers resolve normally). The helper needs Metro 0.68+ (RN 0.68+) for
resolveRequest; this SDK itself targets RN ≥ 0.85 (Expo SDK 56).
5. Add the native permissions manually. The Expo config plugin only runs during
expo prebuild, so a bare app must add the permissions itself — for the features it uses:
ios/<YourApp>/Info.plist:
<key>NSCameraUsageDescription</key> <string>Used for photo attachments and video calls.</string>
<key>NSMicrophoneUsageDescription</key> <string>Used for voice notes and video calls.</string>
<key>NSPhotoLibraryUsageDescription</key><string>Used to attach photos and documents.</string>android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- ONLY if you implement a background-call foreground service (the plugin's `backgroundCall` option): -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />This mirrors exactly what the Expo config plugin injects.
READ_EXTERNAL_STORAGEis capped atmaxSdkVersion="32"(API 33+ usesREAD_MEDIA_*). The twoFOREGROUND_SERVICE*lines are not added by default — only when you opt into a background-call foreground service — so omit them unless you've built that.
6. Rebuild the native app — native modules need a fresh build, not just a Metro reload:
cd ios && pod install && cd .. # iOS only
npx react-native run-ios # or: npx react-native run-androidQuick start
import React from "react";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { WebChat } from "@experiaapp/webchat-react-native";
const CONFIG = {
channelId: "YOUR_CHANNEL_ID",
connectionUrl: "YOUR_SOCKET_HOST",
configUrl: "YOUR_CONFIG_HOST",
language: "en", // "en" | "ar"
};
export default function App() {
return (
<SafeAreaProvider>
<WebChat config={CONFIG} />
</SafeAreaProvider>
);
}That's the whole integration: a floating launcher button appears, and tapping it opens the chat. Branding, title, avatar, and theme come from your channel configuration (fetched via configUrl), so you usually only provide the connection details above.
channelId,connectionUrl, andconfigUrlidentify and connect your channel — you receive these with your Experia account.
Configuration
The config prop carries your connection details. Everything else — video calls, attachments, the pre-chat form, branding, title, avatar, and colors — is configured in your Experia channel and fetched at runtime via configUrl. In most apps you only pass the connection details (plus, optionally, the language):
<WebChat
config={{
channelId: "YOUR_CHANNEL_ID",
connectionUrl: "YOUR_SOCKET_HOST",
configUrl: "YOUR_CONFIG_HOST",
language: "en", // "en" | "ar" — drives RTL (optional)
}}
/>Managed in your Experia channel (no app changes)
Controlled from your channel configuration and applied automatically — you don't set these in code:
- Features: video calls, image / document / voice attachments, emoji picker, typing indicator, "powered by" badge
- Launcher & chrome: default launcher visibility, close button, online/offline status, connecting text
- Branding: theme & colors, header title/subtitle, agent avatar, launcher image
- Pre-chat form: enabled, fields (text / email / phone / dropdown), labels, headline, submit label
- Behavior: history-persistence window, welcome message
Advanced — overriding the channel config
Precedence is prop → channel → default, so you can override any setting per build by passing it on config. This is an escape hatch, not the usual path — e.g. force a pre-chat form or turn video off regardless of the channel:
<WebChat
config={{
channelId: "YOUR_CHANNEL_ID",
connectionUrl: "YOUR_SOCKET_HOST",
configUrl: "YOUR_CONFIG_HOST",
makeVideoCall: false, // override the channel
prechatForm: {
enabled: true,
fields: [{ key: "name", type: "text", label: { en: "Name", ar: "الاسم" }, required: true }],
},
}}
/>Host-side props
These live on the component, not the channel config:
| Prop | Type | Description |
| --- | --- | --- |
| config | object | Connection details (+ optional overrides). Required. |
| open | boolean | Open the surface on mount. |
| title | string | Override the channel's header title. |
| renderLauncher | ({ open }) => ReactNode | Render your own launcher (see below). |
| prechatValues | Record<string, string> | Pre-fill the greeting with known user data. |
| disabledInput | boolean | Lock the composer. |
| secureScreen | boolean | Block screen capture while the chat is open (best-effort). |
Callbacks: onOpen, onClose, onMessageReceived(message), onConnected, onDisconnected, onError(error), onUnreadChange(count).
Controlling the chat (imperative API)
Attach a ref to open/close the chat or manage the session from anywhere in your app:
import { useRef } from "react";
import { WebChat, type WebChatHandle } from "@experiaapp/webchat-react-native";
const chat = useRef<WebChatHandle>(null);
<WebChat ref={chat} config={CONFIG} />;
// elsewhere:
chat.current?.open();
chat.current?.close();
chat.current?.sendMessage("Hello");
chat.current?.getUnreadCount(); // number
chat.current?.clearHistory(); // drop messages, keep the session
chat.current?.resetSession(); // start a new session + clear history
clearHistory()/resetSession()erase the locally stored conversation — call one on user logout.
Customizing the launcher
The default is a round floating button. You can change it four ways:
1. Your own launcher (any shape):
<WebChat
config={CONFIG}
renderLauncher={({ open }) => (
<Pressable onPress={open} style={{ /* a pill, bar, avatar, anything */ }}>
<Text>Chat with us</Text>
</Pressable>
)}
/>2. Trigger from your own UI — hide the built-in button and open via the ref:
<WebChat ref={chat} config={{ ...CONFIG, showButtonChat: false }} />
// <YourButton onPress={() => chat.current?.open()} />3. Reshape the default via channel theme tokens (size, color, corner radius).
4. Use a branded image via the openLauncherImage channel config.
Media & video
- Attachments: images (PNG/JPEG), PDF documents, and voice notes. Picking is gated by the
uploadMedia/upload*flags; selected files are validated against the channel's allow-list before sending. - Video calls: set
makeVideoCall: trueto show the call button (a call can also start automatically when your channel triggers it). Video requires thereact-native-webrtc+react-native-incall-managerpeers, the@config-plugins/react-native-webrtcExpo plugin (managed apps), and a development build.
Notifications: the SDK does not integrate push. Use the onMessageReceived callback to fire your own local notification.
TypeScript
The package ships full type declarations. Import types alongside values:
import { WebChat, type WebChatHandle } from "@experiaapp/webchat-react-native";Lower-level building blocks (the theme helpers, media utilities, individual UI pieces, and the video-call primitives) are also exported if you need to compose a custom surface.
Troubleshooting
- Native feature does nothing / picker won't open in Expo Go — Expo Go can't load the native modules; use a development build (
eas build/expo prebuild). - Icons render as plain glyphs — install
react-native-svg. - Video-call button missing — set
makeVideoCall: true, install the WebRTC peers + plugin, and ensure your channel enables it. - The same conversation keeps resuming — that's
storage: "localStorage"(the default). Use"sessionStorage"to start fresh each launch, or callresetSession().
License
MIT © Experia App — see LICENSE.
