> ## Documentation Index
> Fetch the complete documentation index at: https://docs.typewise.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Embed the chat widget in a mobile app

> Show the Typewise full-page chat inside an iOS or Android app using a WebView

Show the Typewise full-page chat in your native iOS or Android app. Your app
loads a small HTML page in a WebView, and that page loads the chat from
Typewise.

> [!TIP]
>
> Building with React Native or Expo, or want native chat components instead of
> a WebView? Use the [Chat
> SDK](https://docs.typewise.app/guides/channels/chat-sdk/other-frameworks.md#react-native-and-expo).

## Prerequisites

* Your **client ID**. Find it under **Behavior → Channels → Chat →
  Installation**, in the Quick start snippet.
* Every variable you pass is declared in
  [Context Variables](https://docs.typewise.app/documentation/settings/context-variables.md).

## The chat page

The WebView loads this HTML. It sets `window.twConfig` and loads the full-page
chat script:

```html theme={null}
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Chat</title>
  </head>
  <body>
    <script>
      window.twConfig = {
        clientId: "YOUR_CLIENT_ID",
        variables: {
          user_email: "user@example.com",
        },
      };
    </script>
    <script
      type="module"
      src="https://platform.typewise.app/sdk/sdk-fullpage.js"
    ></script>
  </body>
</html>
```

**clientId** `string` *required*

Your Typewise chat client ID.

**variables** `object`

Context about the signed-in user, such as `user_email`. These values are
unverified.

**signedVariables** `string`

A JWT from your backend, for values that must pass the **Trusted only** check.
See [Identity
verification](https://docs.typewise.app/guides/channels/chat-widget/identity-verification.md).

Build this HTML in your app so each user gets their own `clientId` and
`variables`. Serialize the configuration as JSON instead of pasting values into
the script, so a quote or `</script>` in a value can't break the page or inject
code. Load it with `https://platform.typewise.app/` as the base URL, so the
script and its resources resolve correctly.

## Load it in a WebView

**iOS (Swift)**

**1. Add a WKWebView**

Present a full-screen `WKWebView` from a view controller or SwiftUI
view, constrained to the safe area or the full screen.

**2. Build the HTML**

```swift theme={null}
let clientId = "YOUR_CLIENT_ID"     // from your config
let userEmail = "user@example.com"  // from your auth layer

let config: [String: Any] = [
    "clientId": clientId,
    "variables": ["user_email": userEmail],
]
let configJson = String(
    data: try JSONSerialization.data(withJSONObject: config),
    encoding: .utf8
)!.replacingOccurrences(of: "<", with: "\\u003c")

let html = """
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Chat</title>
  </head>
  <body>
    <script>
      window.twConfig = \(configJson);
    </script>
    <script type="module" src="https://platform.typewise.app/sdk/sdk-fullpage.js"></script>
  </body>
</html>
"""
```

**3. Load the HTML with the Typewise base URL**

```swift theme={null}
import WebKit

let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
webView.loadHTMLString(html, baseURL: URL(string: "https://platform.typewise.app/")!)
```

`WKWebView` runs JavaScript by default. If you pass a custom
`WKWebViewConfiguration`, don't disable it.

**Android (Kotlin)**

**1. Add a WebView**

Add a `WebView` to your Activity or Fragment layout, in XML or Compose.

**2. Enable JavaScript and DOM storage**

The chat needs both to run:

```kotlin theme={null}
val webView: WebView = findViewById(R.id.webView)
webView.settings.apply {
    javaScriptEnabled = true
    domStorageEnabled = true
}
```

**3. Build the HTML**

```kotlin theme={null}
import org.json.JSONObject

val clientId = "YOUR_CLIENT_ID"     // from your config
val userEmail = "user@example.com"  // from your auth layer

val configJson = JSONObject()
    .put("clientId", clientId)
    .put("variables", JSONObject().put("user_email", userEmail))
    .toString()
    .replace("<", "\\u003c")

val html = """
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Chat</title>
  </head>
  <body>
    <script>
      window.twConfig = $configJson;
    </script>
    <script type="module" src="https://platform.typewise.app/sdk/sdk-fullpage.js"></script>
  </body>
</html>
""".trimIndent()
```

**4. Load the HTML with the Typewise base URL**

```kotlin theme={null}
webView.loadDataWithBaseURL(
    "https://platform.typewise.app/",
    html,
    "text/html",
    "utf-8",
    null
)
```

The chat needs only HTTPS, so leave `android:usesCleartextTraffic`
unset or `false`. If you set a custom `WebViewClient`, make sure it
doesn't block `platform.typewise.app`.

## Domain allowlist

While your chat's **Domain allowlist** is empty, the chat loads from any origin,
including a WebView.

If you've added domains, the WebView must load from an allowed origin. Loading
the HTML with the base URL `https://platform.typewise.app/` covers this. If you
use a different base URL, add that origin under **Behavior → Channels → Chat →
Installation**, or contact support to allow your app.

## Troubleshooting

> **The WebView stays blank**
>
> Check that JavaScript is enabled (and DOM storage on Android), and that the
> base URL is `https://platform.typewise.app/`. If your app applies a Content
> Security Policy, allow the domains in [Configure
> CSP](https://docs.typewise.app/guides/channels/chat-widget/content-security-policy.md).

> **The chat fails with a domain or origin error**
>
> The WebView's origin isn't in your Domain allowlist. See [Domain
> allowlist](#domain-allowlist).

For other issues, see
[Chat widget troubleshooting](https://docs.typewise.app/documentation/troubleshooting/chat-widget.md).

## Related

* [Identity verification](https://docs.typewise.app/guides/channels/chat-widget/identity-verification.md):
  pass the user's identity as verified values
* [Chat configuration](https://docs.typewise.app/documentation/behavior/chat.md): appearance, guidance, and
  installation


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.