Busymate AI

Guías

Soporte con IA dentro de la app para iOS y Android

Muestre el chat de su asistente dentro de su app de iOS o Android, pase el inicio de sesión por su propia API y pruébelo en un dispositivo real.

YOUR APPCHANNEL?channel=iosWeb viewBRIDGEWeb viewBusymateAIIdentityOpen linkClose
En esta página

Your app gets Busymate AI support by showing your assistant's chat inside a WKWebView (iOS) or a WebView (Android) with channel=ios or channel=android. Your own API vouches for signed-in customers through a small bridge, so they are recognized. If your app runs a proxy or VPN, keep the chat host out of it. There is no SDK binary — two source files you copy.

1. Load the hosted chat

  1. The app loads the hosted chat: https://<your-host>/?channel=ios (or channel=android). Your own address is the entry point; the platform keeps /support/<slug> as a fallback.
  2. The page asks the native side for identity through a small bridge. A signed-in customer gets an identified session; a signed-out one is anonymous.
  3. External links open outside the WebView; the chat stays inside your app.

Loading the bare address is not enough. A WebView that opens https://<your-host>/ with no channel and no bridge gets an anonymous session on every open, for every customer — the page has nobody to ask. Your customers then see an assistant that cannot read their account, however thoroughly they are signed in to your app. Pin the channel and install the bridge in the same change; identity is what makes the assistant theirs.

2. Bridge on iOS

Load the URL in a WKWebView and add a script message handler named BusymateAI. The page posts busymate.ai.v1.identity_request; you answer with busymate.ai.v1.identity carrying { token, nonce }. busymate.ai.v1.open_url asks you to open a link in Safari; busymate.ai.v1.close asks you to dismiss the sheet. The reference source is served at /sdk/v1/ios/BusymateAI.swift.

swift
// SDK source: https://busymate.ai/sdk/v1/ios/BusymateAI.swift
// Load https://your-assistant.busymate.ai/?channel=ios in a WKWebView.
final class AssistantBridge: NSObject, WKScriptMessageHandler {
  let webView: WKWebView

  func userContentController(_ controller: WKUserContentController,
                             didReceive message: WKScriptMessage) {
    guard message.name == "BusymateAI",
          let body = message.body as? [String: Any],
          body["type"] as? String == "busymate.ai.v1.identity_request"
    else { return }

    Task { // mint through YOUR authenticated API — never a key in the app
      let identity = try await api.mintLaunchIdentity()
      let payload: [String: Any] = [
        "type": "busymate.ai.v1.identity",
        "token": identity.token,
        "nonce": identity.nonce,
      ]
      let data = try JSONSerialization.data(withJSONObject: payload)
      let json = String(decoding: data, as: UTF8.self)
      await webView.evaluateJavaScript("window.postMessage(\(json), '*')")
    }
  }
}

3. Bridge on Android

Load the URL in a WebView, enable JavaScript, and register the bridge as BusymateAINative. Same message types, same identity answer. The reference source is served at /sdk/v1/android/BusymateAI.kt.

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.

4. Mint identity

  • The token is a short-lived sign-in proof (an ES256 launch token) your API mints for the signed-in customer — see Recognize signed-in customers.
  • It lives at most 120 seconds and carries a one-time nonce and jti. Mint a fresh pair for every request; never cache one.
  • The signing key stays on your server. The app calls your authenticated API; it never holds a key.
  • Signed out: answer with no identity. The session stays anonymous, with guest access if you allow it.

5. Signed out, or not wired yet

Anonymous is a supported state, not a broken one — with guest access on, the assistant answers product questions for anyone. What it will NOT do in your app is send your customer to a web login page: inside an app, sign-in is handed to the chat by the app, so there is no page for them to use. It says plainly that this chat has not been given their account yet and that the app has to pass their sign-in through, then helps with everything that does not need an account. The in-chat Sign in control appears only where it can finish — a browser, an iframe embed, or an app that installed the bridge — so your customers are never pointed at a control that goes nowhere.

6. Match your app

The hosted chat follows the device's light or dark setting and the customer's language. The name, colors and welcome copy come from your workspace branding, so the sheet reads as part of your app.

7. Keep it out of your proxy

Exclude your own process — or at least the chat host — from the tunnel. Otherwise the WebView's traffic loops through your own capture and the sheet stalls.

Real example

Our own DevTools iOS and Android apps show their own workspace this way: a Support tab, a WebView, the bridge above, identity minted by the DevTools API for signed-in customers. It is Rolling out through TestFlight and the internal Play track — follow the changelog. The integration is written up as a public page: DevTools integration.

Verify

On a device, not a simulator:

  1. Signed out, open Support. Guest chat answers.
  2. Sign in and reopen. The greeting identifies the customer; history is theirs.
  3. Tap an external link. It opens in the system browser.
  4. Log out. The next identity request returns nothing; the session is anonymous again.
  5. Write "talk to a human". The request reaches the Inbox.

Next

Preguntas

Do I need a native SDK?

No. A WebView plus the bridge source file for your platform. Both files are served from the platform and versioned under /sdk/v1/.

Where does the identity token come from?

From your own API, for your own signed-in customer. The app never holds a signing key; it forwards what your API minted.

Does the chat match my app's look?

Branding is your workspace's — name, colors, welcome copy. Light and dark follow the device.

Can I ship this before identity is wired?

Yes. Without a bridge answer the chat runs anonymously. Add identity when your API is ready; the page starts asking for it on the next open.