diff --git a/docs.json b/docs.json
index 079060fc..52a3a09a 100644
--- a/docs.json
+++ b/docs.json
@@ -426,7 +426,8 @@
"pages": [
"/webchat/integrations/wordpress",
"/webchat/integrations/wix",
- "/webchat/integrations/webflow"
+ "/webchat/integrations/webflow",
+ "/webchat/integrations/react-native"
]
},
{
diff --git a/webchat/integrations/react-native.mdx b/webchat/integrations/react-native.mdx
new file mode 100644
index 00000000..3bf1ca99
--- /dev/null
+++ b/webchat/integrations/react-native.mdx
@@ -0,0 +1,384 @@
+---
+title: React Native
+description: Add your bot in any React Native or Expo app using react-native-webview.
+---
+
+
+**Why a WebView?** Botpress Cloud Webchat is a **browser** client (`window.botpress`). React Native does not run that API natively, so the supported pattern is to run the official Webchat **inside a WebView** and communicate with `postMessage` and `injectJavaScript`.
+
+The [`@botpress/webchat`](/webchat/react-library/get-started) package targets web React. For native apps, use the WebView approach below.
+
+
+## Prerequisites
+
+
+You will need:
+
+* A [published bot](/get-started/quick-start)
+* A React Native or Expo project
+* [`react-native-webview`](https://github.com/react-native-webview/react-native-webview)
+
+
+## 1. Copy your Webchat embed code from the dashboard
+
+Before you write any app code, grab the same embed snippet you would use on a website. In the Botpress dashboard:
+
+1. Open your bot's Workspace and select the bot you want to embed.
+2. In the left sidebar, go to **Webchat** > **Deploy Settings**.
+3. Copy the **Embed code**:
+
+
+
+
+
+
+## 2. Lay out your project files
+
+Create a **`src`** folder at your project root if you do not already have one. A typical layout:
+
+| Path | Purpose |
+|------|---------|
+| **`src/botpress/getBotpressWebchat.js`** | Builds `{ html, baseUrl }` for the WebView. |
+| **`src/botpress/BpWidget.js`** | WebView component and event bridge (`onMessage`); blocks marketing site navigation on close. |
+| **`src/botpress/BpWidget.d.ts`** | *(Optional, TypeScript only)* Types for `BpWidget`. |
+| **`src/config/botpressConfig.js`** | Webchat URLs and optional `botId`. **Step 4** shows what goes inside `export const botpressConfig = { ... }`. |
+
+You can instead keep files flat under `src/` and use relative imports. The examples below assume **`src/botpress/`** and **`src/config/`**.
+
+**Path alias (optional, Expo / TypeScript):** In **`tsconfig.json`**, merge into `compilerOptions`:
+
+```json
+{
+ "compilerOptions": {
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ }
+}
+```
+
+Then imports like `import BpWidget from '@/botpress/BpWidget'` resolve. If you skip aliases, use relative imports only.
+
+## 3. Install react-native-webview
+
+From your project root:
+
+
+
+```bash Expo
+npx expo install react-native-webview
+```
+
+```bash npm
+npm install react-native-webview
+```
+
+```bash yarn
+yarn add react-native-webview
+```
+
+```bash pnpm
+pnpm add react-native-webview
+```
+
+
+
+
+ For bare React Native, follow [react-native-webview linking](https://github.com/react-native-webview/react-native-webview/blob/master/docs/Getting-Started.md) if your setup requires it. Expo users can also see the [Expo WebView docs](https://docs.expo.dev/versions/latest/sdk/webview/).
+
+
+## 4. Save your Studio script URLs in one config file
+
+Create **`src/config/botpressConfig.js`** and export a single **`botpressConfig`** object. Paste the script URLs from **Studio → Webchat → Embed** (the same values from your embed snippet). The HTML helper and the widget only read **`botConfig`**: you pass it in, and you do not duplicate URLs inside `getBotpressWebchat.js` or `BpWidget.js`.
+
+
+**Sensitive values:** `botId` and embed URLs identify your bot. For a public repository, do not commit real values, use placeholders in git or keep this file out of version control.
+
+
+
+```javascript
+export const botpressConfig = {
+ botId: "YOUR_BOT_ID",
+ injectScriptUrl: "https://cdn.botpress.cloud/webchat/v3.6/inject.js",
+ embedScriptUrl: "https://files.bpcontent.cloud/YOUR/PATH/YOUR-GENERATED.js",
+ baseUrl: "https://cdn.botpress.cloud/",
+};
+```
+
+
+## 5. Build the HTML page that loads Webchat
+
+Add **`src/botpress/getBotpressWebchat.js`**. It builds a tiny HTML page (inject script, embed script, full height container) and returns **`{ html, baseUrl }`** so you can pass it straight into ``.
+
+```javascript getBotpressWebchat.js
+/**
+ * Builds the HTML page loaded by the WebView for Botpress Cloud webchat v3.
+ * @param {Record} botConfig Pass `botpressConfig` from src/config/botpressConfig.js
+ * @returns {{ html: string, baseUrl: string }}
+ */
+const getBotpressWebchat = (botConfig) => {
+ // Official inject script (Botpress loader); falls back to a known default if omitted.
+ const injectUrl =
+ botConfig.injectScriptUrl ||
+ "https://cdn.botpress.cloud/webchat/v3.6/inject.js";
+ // Studio-generated bundle URL (required). This wires your bot into the page.
+ const embedUrl = botConfig.embedScriptUrl;
+ if (!embedUrl || typeof embedUrl !== "string") {
+ throw new Error(
+ "botConfig.embedScriptUrl is required (paste the second script URL from Studio embed)",
+ );
+ }
+ // Origin passed to WebView as `baseUrl` so relative URLs in the HTML resolve correctly.
+ const baseUrl = botConfig.baseUrl || "https://cdn.botpress.cloud/";
+
+ // Minimal HTML shell: viewport, full-height container, then inject + embed scripts (matches Studio order).
+ const html = `
+
+
+
+
+
+ Chatbot
+
+
+
+
+
+`;
+
+ // WebView expects this pair: `source={{ baseUrl, html }}`.
+ return { baseUrl, html };
+};
+
+module.exports = getBotpressWebchat;
+```
+
+## 6. Show Webchat in a WebView and forward events to React Native
+
+Create **`src/botpress/BpWidget.js`**. It renders a **`WebView`** that loads your HTML, then relays what happens inside the page to your React Native layer:
+
+* Puts the page from **`getBotpressWebchat(botConfig)`** into the **`WebView`**.
+* Injects a script that subscribes to **`window.botpress`** and sends each event to React Native with **`postMessage`** (you read them in **`onMessage`** as JSON strings).
+* Intercepts navigation to **`botpress.com`** or **`*.botpress.com`** when the user closes the widget and runs **`window.botpress.close()`** instead to close the webchat interface.
+
+```javascript BpWidget.js expandable
+/**
+ * WebView wrapper for Botpress webchat v3: window.botpress API, events to React Native via postMessage.
+ */
+import { WebView } from "react-native-webview";
+import getBotpressWebchat from "./getBotpressWebchat";
+import React, { useCallback, useRef } from "react";
+
+const broadcastToReactNative = `
+(function () {
+ // Sends one event payload to React Native as a JSON string (read in onMessage).
+ function post(ev, data) {
+ try {
+ window.ReactNativeWebView.postMessage(JSON.stringify({ event: ev, data: data }));
+ } catch (e) {}
+ }
+ // Subscribes to window.botpress once it exists and mirrors events into React Native.
+ function wire() {
+ if (!window.botpress || typeof window.botpress.on !== "function") return false;
+ window.botpress.on("webchat:initialized", function () {
+ try { window.botpress.open(); } catch (e) {}
+ });
+ [
+ "message",
+ "webchat:initialized",
+ "webchat:ready",
+ "webchat:opened",
+ "webchat:closed",
+ "customEvent",
+ "error",
+ "conversation",
+ ].forEach(function (ev) {
+ window.botpress.on(ev, function (data) {
+ post(ev, data);
+ });
+ });
+ // Fallback open in case the widget did not auto-open after init.
+ setTimeout(function () {
+ try { window.botpress.open(); } catch (e) {}
+ }, 400);
+ return true;
+ }
+ // Poll until botpress is ready (or give up after ~12s) so inject order does not race.
+ var n = 0;
+ var id = setInterval(function () {
+ if (wire() || ++n > 240) clearInterval(id);
+ }, 50);
+})();
+true;
+`;
+
+const closeChatJs = `
+try {
+ // Programmatic close when we block a navigation attempt (through onShouldStartLoadWithRequest).
+ if (window.botpress && typeof window.botpress.close === "function") {
+ window.botpress.close();
+ }
+} catch (e) {}
+true;
+`;
+
+// Returns true when a navigation URL is the public Botpress marketing site (close button behavior).
+function isBotpressMarketingSiteUrl(url) {
+ if (!url || url.startsWith("about:") || url.startsWith("blob:") || url.startsWith("data:")) {
+ return false;
+ }
+ try {
+ const h = new URL(url).hostname;
+ return h === "botpress.com" || h.endsWith(".botpress.com");
+ } catch {
+ return false;
+ }
+}
+
+export default function BpWidget(props) {
+ const { botConfig, onMessage } = props;
+ const webref = useRef(null);
+
+ // Build the in-memory HTML page and origin for this WebView instance.
+ const { html, baseUrl } = getBotpressWebchat(botConfig);
+
+ // Intercept navigations: block opening botpress.com inside the frame and close chat instead.
+ const onShouldStartLoadWithRequest = useCallback((request) => {
+ const { url } = request;
+ if (isBotpressMarketingSiteUrl(url)) {
+ webref.current?.injectJavaScript(closeChatJs);
+ return false;
+ }
+ return true;
+ }, []);
+
+ // Webchat needs JavaScript and DOM storage; originWhitelist allows loading scripts from Botpress CDNs.
+ return (
+
+ );
+}
+```
+
+
+ **`onMessage` format:** `event.nativeEvent.data` is a **string**. Parse with `JSON.parse`. Shape: **`{ event: string, data: unknown }`**.
+
+
+## 7. Optional: add TypeScript types for the widget
+
+If you use TypeScript, add **`src/botpress/BpWidget.d.ts`** next to **`BpWidget.js`** so imports and props are typed:
+
+```typescript
+import type { FunctionComponent } from "react";
+
+/** Props for the WebView wrapper: Studio-derived config and optional React Native message handler. */
+export interface BpWidgetProps {
+ botConfig: Record;
+ onMessage?: (e: { nativeEvent: { data: string } }) => void;
+}
+
+/** Default export from BpWidget.js (JavaScript component with these props). */
+declare const BpWidget: FunctionComponent;
+
+export default BpWidget;
+```
+
+## 8. Render the Webchat widget on a screen
+
+Import **`BpWidget`** and **`botpressConfig`**, then render it full screen or inside any `View` that uses `flex: 1`. Adjust import paths to your real paths (for example Expo Router **`app/index.tsx`**, a root **`App.js`**, or **`src/screens/…`**).
+
+```tsx ChatScreen.tsx
+import { StyleSheet, View } from "react-native";
+import { SafeAreaView } from "react-native-safe-area-context";
+
+import BpWidget from "@/botpress/BpWidget";
+import { botpressConfig } from "@/config/botpressConfig";
+
+/** Screen that fills the safe area with the Botpress WebView-powered widget. */
+export default function ChatScreen() {
+ return (
+
+
+ {
+ // Bridge: WebView posts JSON strings; parse to `{ event, data }` for logging or app logic.
+ const raw = e.nativeEvent?.data;
+ if (!raw) return;
+ try {
+ const msg = JSON.parse(raw);
+ console.log(msg.event, msg.data);
+ } catch {
+ /* non-JSON */
+ }
+ }}
+ />
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ safeArea: { flex: 1 },
+ main: { flex: 1 },
+});
+```
+
+## 9. Run your app
+
+```bash
+npm install
+npx expo start
+```
+
+
+Open the iOS Simulator, Android emulator, or a physical device from there. Your bot should load inside the WebView when you run the app.
+
+
+
+## Troubleshooting
+
+| Problem | What to check |
+|--------|----------------|
+| Blank WebView | **`embedScriptUrl`** in **`botpressConfig.js`** must be the **`files.bpcontent.cloud/...`** URL from Studio. |
+| Error: `embedScriptUrl is required` | Set `embedScriptUrl` in `botpressConfig`. |
+| Close (X) opens the Botpress.com website | Keep **`onShouldStartLoadWithRequest`** and **`closeChatJs`** in `BpWidget.js` as shown in that section. |
+| Fonts look wrong | Tune appearance in **Botpress Studio**; avoid forcing global `font-family` in the HTML shell. |
+| Android keyboard covers the composer | In **`app.json`** (Expo), under **`expo.android`**, set `"softwareKeyboardLayoutMode": "resize"`. Rebuild the native Android app after changing this (not only a Metro refresh). |
+
+## Next steps
+
+Now that Webchat runs in your app, try [styling](/webchat/get-started/configure-your-webchat) it in Studio to match your product. For more control over the embed, see [Embed Webchat](/webchat/get-started/embedding-webchat) and the [Webchat interaction reference](/webchat/interact/reference).