> ## 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.

Load the Typewise full-page chat inside your native iOS or Android app by
opening a WebView with the chat HTML. This guide walks you through the HTML to
use and how to implement it on both platforms.

## Overview

The chat runs in a WebView that loads an HTML page. The page includes the
Typewise full-page SDK script and a config object with your **client ID** and
optional **variables** (e.g. `user_email`). You host this HTML inside your app
(e.g. as a local asset or inline string) and load it in a WebView so the script
can fetch the chat UI from Typewise.

<Info>
  You need a **client ID** from the Typewise platform. Get it from **Behavior →
  Channels → Chat → Installation** (Quick start section).
</Info>

## HTML to load in the WebView

Use the following HTML in your WebView. Replace `YOUR_CLIENT_ID` with your
actual client ID. You can pass user data via `variables` for personalization.
To pass values that satisfy the **Trusted only** check on action or lookup
inputs, sign them server-side and pass them as `signedVariables`. See
[Chat identity verification](/guides/channels/chat-identity-verification).

```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-fullpage.js"
    ></script>
  </body>
</html>
```

* **clientId** (required): Your Typewise chat client ID.
* **variables** (optional): Key-value pairs to identify the user (e.g.
  `user_email`). Use your app’s signed-in user data; you can add or remove keys
  as needed.

<Tip>
  Ensure your app injects or replaces `YOUR_CLIENT_ID` and the `variables`
  values (e.g. from your auth layer) so each user gets the correct context.
</Tip>

***

## iOS (Swift)

Use `WKWebView` to load the chat HTML. Load the HTML string with a base URL so
the script can load from `https://platform.typewise.app/`.

<Steps>
  <Step title="Add a WebView to your flow">
    Create a view controller (or SwiftUI view) that presents a full-screen `WKWebView`. Add the WebView to your view hierarchy and constrain it to the safe area or full screen.
  </Step>

  <Step title="Build the HTML string">
    Build the HTML in code so you can set `clientId` and `variables` from your app (e.g. from your config and logged-in user).

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

    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 = {
            clientId: "\(clientId)",
            variables: {
              user_email: "\(userEmail)",
            },
          }
        </script>
        <script
          type="module"
          src="https://platform.typewise.app/sdk-fullpage.js"
        ></script>
      </body>
    </html>
    """
    ```
  </Step>

  <Step title="Load the HTML in the WebView">
    Load the HTML with `loadHTMLString(_:baseURL:)` and use `https://platform.typewise.app/` as the base URL so the script and resources load correctly.

    ```swift theme={null}
    import WebKit

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

  <Step title="Enable JavaScript and allow inline content">
    `WKWebView` has JavaScript enabled by default. If you use a custom `WKWebViewConfiguration`, ensure you don’t disable script. For mixed content (HTTPS script on a loaded HTML string), the default configuration is usually sufficient.

    <Note>
      If your app uses a strict Content Security Policy or custom WKWebView configuration, see [Configure CSP for the chat widget](/guides/channels/content-security-policy) for the full list of required domains.
    </Note>
  </Step>
</Steps>

***

## Android (Kotlin)

Use the system `WebView` to load the chat HTML. Load the HTML with a base URL so
the script can load from Typewise.

<Steps>
  <Step title="Add a WebView to your screen">
    Add a `WebView` to your Activity or Fragment layout (e.g. in XML or Compose) and give it a stable ID so you can reference it in code.
  </Step>

  <Step title="Enable JavaScript and DOM storage">
    In your Activity or Fragment, get the `WebView` and enable JavaScript and DOM storage so the SDK runs correctly.

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

  <Step title="Build the HTML string">
    Build the HTML in code so you can set `clientId` and `variables` from your app (e.g. from your config and logged-in user).

    ```kotlin theme={null}
    val clientId = "YOUR_CLIENT_ID"  // From your config or backend
    val userEmail = "user@example.com"  // From your auth

    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 = {
            clientId: "$clientId",
            variables: {
              user_email: "$userEmail",
            },
          }
        </script>
        <script
          type="module"
          src="https://platform.typewise.app/sdk-fullpage.js"
        ></script>
      </body>
    </html>
    """.trimIndent()
    ```
  </Step>

  <Step title="Load the HTML with a base URL">
    Use `loadDataWithBaseURL` so the relative script URL resolves to `https://platform.typewise.app/`. Use `"utf-8"` for encoding and `"text/html"` for the MIME type.

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

  <Step title="Handle mixed content and HTTPS (if needed)">
    On Android 5 and above, mixed content is restricted by default. Because the page is loaded via `data`/base URL and the script is HTTPS, it should work. If you see blocked requests, ensure your WebView allows HTTPS and that you’re not overriding with a custom `WebViewClient` that blocks `platform.typewise.app`.

    <Note>
      Add `android:usesCleartextTraffic="false"` (or leave it unset) and ensure your app allows HTTPS to `platform.typewise.app`. No cleartext traffic is required for the chat.
    </Note>
  </Step>
</Steps>

***

## Domain allowlist

For the chat to load in your app’s WebView, the Typewise **Domain allowlist**
must allow your app’s context. While no domains are configured, the allowlist
restricts nothing and the widget loads from any origin.

* **iOS:** Add your app’s custom URL scheme or bundle ID if you use a custom
  base URL; if you load with base URL `https://platform.typewise.app/`, the
  script origin is already allowed. If Typewise validates the “referrer” or
  origin, ask support to allow your app (e.g. by bundle ID or a dedicated
  scheme).
* **Android:** Similarly, if validation is applied, the allowlist may need to
  include your app (e.g. custom scheme or package name).

If the chat fails to load with a domain/origin error, go to **Behavior →
Channels → Chat → Installation** and add the origin or app identifier your
WebView uses, or contact support to allow your mobile app.

## See also

* [Chat Configuration](/documentation/behavior/chat): Guidance, appearance, and
  installation
* [Chat widget troubleshooting](/documentation/troubleshooting/chat-widget):
  Script not loading or no activity
* [Configure CSP for the chat widget](/guides/channels/content-security-policy):
  Required CSP directives for sites with security headers
