--- title: "Recognize signed-in customers in React Native | Busymate AI" description: "Copy one shim, inject it before content loads, and answer the same four identity messages every native bridge answers — one WebView, either platform." --- # Recognize signed-in customers in React Native | Busymate AI Source: https://busymate.ai/de/docs/guides/identity-react-native Busymate AI reaches a React Native app the same way it reaches any native shell: a small bridge answers who is signed in. React Native hides both platforms' native bridges behind one `WebView` component, so the kit installs a single shim that speaks the same wire messages on either OS. ## 1. Copy the shim Copy `https://busymate.ai/sdk/v1/kit/react-native/busymateIdentity.js` into your app. It installs the Android-shaped interface on the page and forwards every message to your own `onMessage` handler — the same four messages every platform answers. ## 2. Inject before content loads, not after Pass the shim's source to your `WebView` as `injectedJavaScriptBeforeContentLoaded`, and forward everything it posts back to `bridge.onMessage(event.nativeEvent.data, event.nativeEvent.url)` from the component's own `onMessage` prop — the full wiring is in the runnable sample below. Use `injectedJavaScriptBeforeContentLoaded`, never `injectedJavaScript`: the latter runs after load, so the very first identity ask can arrive before your bridge exists and gets no answer at all. ## 3. What the shim mimics underneath On Android the underlying interface looks like this — the shim gives your page the identical shape without you writing it: ```kotlin // SDK source: https://busymate.ai/sdk/v1/android/BusymateAI.kt // Load https://your-assistant.busymate.ai/?channel=android in a WebView. class AssistantBridge(private val webView: WebView) { @JavascriptInterface fun postMessage(raw: String) { val message = JSONObject(raw) if (message.optString("type") != "busymate.ai.v1.identity_request") return lifecycleScope.launch { // mint through YOUR authenticated API client val identity = api.mintLaunchIdentity() val response = JSONObject() .put("type", "busymate.ai.v1.identity") .put("token", identity.token) .put("nonce", identity.nonce) webView.evaluateJavascript( "window.postMessage(${JSONObject.quote(response.toString())}, '*')", null ) } } } webView.settings.javaScriptEnabled = true webView.addJavascriptInterface(AssistantBridge(webView), "BusymateAINative") // SupportChatNative + support.chat.v1.* remain accepted for shipped apps. ``` Your own `identityProvider` calls your authenticated API on every ask, never a cached value; `bridge.identityChanged()` on login, rotation or account switch; `bridge.signedOut()` on logout. ## 4. Run the sample first `https://busymate.ai/sdk/v1/kit/react-native/Sample.jsx` is a working screen: a fake sign-in toggle, the shim installed, the widget reacting to both directions. Confirm it behaves before wiring your own auth store in. ## Verify 1. Signed out, open the screen: the assistant runs an anonymous, guest session. 2. Sign in inside your app, without reloading the WebView, and call `identityChanged()`: the same thread becomes identified. 3. Background the app past the token's lifetime, then foreground it: the assistant re-asks and gets a fresh answer, not a refused stale one. 4. Sign out and reopen the screen: the previous customer's history is gone, not merely hidden. 5. Run `node v2/scripts/identity-conformance.mjs --host --json` against `channel=android`; React Native answers through the same wire shape the checker already grades. ### Do I need a separate integration for iOS builds of the same app? No. The `WebView` component and this shim are the same on both platforms; only your native project's build configuration differs, not this bridge. ### Why can't I use `injectedJavaScript` — it is simpler to reason about? It runs once the page has already loaded, which is after the assistant's first identity ask. A handler installed that late misses the one ask that matters most, the first one. ### Does the shim work with Expo's managed WebView? Any component built on `react-native-webview` accepts the same two props (`injectedJavaScriptBeforeContentLoaded`, `onMessage`), so the shim asks nothing extra of your bundler or build tool. ### What if my app never installs the shim? The assistant still runs, anonymously. A missing bridge is a supported, guest state — never a broken chat — until you wire identity in. ## Next - **[Recognize signed-in customers](https://busymate.ai/de/docs/guides/identified-visitors)** — the four obligations this bridge answers. - **[In-app AI support for iOS and Android](https://busymate.ai/de/docs/guides/mobile-in-app-support)** — the native bridge this shim mirrors. - **[Fix a signed-in customer who shows as a guest](https://busymate.ai/de/docs/guides/identity-troubleshooting)** — symptom-first fixes when a cell fails.