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

# Mobile Support

> Add OpenCX AI chat to your iOS, Android, or React Native app with a WebView support screen.

Use this page when you want customers to open chat inside your mobile app.

<Tip>
  Build one support page, load it in a WebView, and let OpenCX handle the conversation.
</Tip>

## What You Are Building

Add a **Support** screen to your app. That screen opens a WebView pointed at a small HTTPS page with the OpenCX widget already open.

## Implementation Steps

<Steps>
  <Step title="Create a support page">
    Host a page like `https://app.example.com/mobile-support`. Your app will load this URL in a WebView.
  </Step>

  <Step title="Add the widget">
    Give the page a real viewport height. Without this, the widget can load but the chat input may sit too high on the screen.

    ```html support.html theme={"dark"}
    <style>
      html,
      body {
        margin: 0;
        width: 100%;
        height: 100%;
        overflow: hidden;
      }

      #opencx-root {
        width: 100vw;
        height: 100dvh;
      }
    </style>

    <script defer src="https://unpkg.com/@opencx/widget@latest/dist-embed/script.js"></script>
    <script>
      window.addEventListener('DOMContentLoaded', () => {
        initOpenScript({
          token: '<WIDGET_TOKEN>',
          inline: true,
          isOpen: true,
          router: {
            chatScreenOnly: true,
            goToChatIfNoSessions: true,
          },
          theme: {
            screens: {
              chat: {
                width: '100vw',
                height: '100vh',
              },
            },
          },
        });
      });
    </script>
    ```
  </Step>

  <Step title="Open the page from your app">
    Add a Support button, Help Center row, or Account menu item that opens the WebView.
  </Step>

  <Step title="Test the mobile flow">
    Open the app, start a chat, close the screen, reopen it, and confirm the conversation still feels natural.
  </Step>
</Steps>

## Open The WebView

<Tabs>
  <Tab title="React Native">
    Install `react-native-webview` first if your app does not already use it.

    ```tsx SupportScreen.tsx theme={"dark"}
    import { WebView } from 'react-native-webview';

    export function SupportScreen({ supportUrl }: { supportUrl: string }) {
      return (
        <WebView
          source={{ uri: supportUrl }}
          javaScriptEnabled
          domStorageEnabled
          allowsInlineMediaPlayback
          onMessage={(event) => {
            const payload = JSON.parse(event.nativeEvent.data);
            if (payload.type === 'opencx.handoff') {
              // Show a native banner, analytics event, or routing hint.
            }
          }}
        />
      );
    }
    ```
  </Tab>

  <Tab title="iOS">
    ```text SupportViewController.swift theme={"dark"}
    import UIKit
    import WebKit

    final class SupportViewController: UIViewController {
      private let webView = WKWebView()

      override func viewDidLoad() {
        super.viewDidLoad()
        view = webView

        let url = URL(string: "https://app.example.com/mobile-support")!
        webView.load(URLRequest(url: url))
      }
    }
    ```
  </Tab>

  <Tab title="Android">
    ```text SupportActivity.kt theme={"dark"}
    import android.os.Bundle
    import android.webkit.WebView
    import androidx.appcompat.app.AppCompatActivity

    class SupportActivity : AppCompatActivity() {
      override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val webView = WebView(this)
        setContentView(webView)

        webView.settings.javaScriptEnabled = true
        webView.settings.domStorageEnabled = true
        webView.loadUrl("https://app.example.com/mobile-support")
      }
    }
    ```
  </Tab>
</Tabs>

## Recognize Signed-In Customers

If customers sign in to your app, pass a verified contact token to the widget. This lets the same customer see their support history across devices.

<Steps>
  <Step title="Request a token from your backend">
    Your backend calls OpenCX with your org API key. Do not call this from the mobile app.

    ```ts theme={"dark"}
    const response = await fetch('https://api.open.cx/widget/authenticate-user', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.OPENCX_API_KEY}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        email: user.email,
        name: user.name,
        customData: {
          customerId: user.id,
          plan: user.plan,
        },
      }),
    });

    const { token } = await response.json();
    ```
  </Step>

  <Step title="Pass the token into the widget">
    Add the token to your support page config. Your backend can render it into the page or your app can request it before opening the WebView.

    ```js theme={"dark"}
    initOpenScript({
      token: '<WIDGET_TOKEN>',
      inline: true,
      isOpen: true,
      user: {
        token: '<AUTHENTICATED_CONTACT_TOKEN>',
        externalId: '<CURRENT_ACCOUNT_ID>',
      },
    });
    ```
  </Step>
</Steps>

<Warning>
  Never put your OpenCX API key in the mobile app. Keep it on your backend.
</Warning>

## Send Useful Context

Give support enough context to help without asking the customer to repeat themselves.

```js theme={"dark"}
initOpenScript({
  token: '<WIDGET_TOKEN>',
  inline: true,
  isOpen: true,
  context: 'Customer is viewing order ORD-123 in the iOS app.',
  sessionCustomData: {
    platform: 'ios',
    appVersion: '8.4.0',
    accountId: 'acct_123',
  },
});
```

Keep this clean. Send account IDs, plan names, app version, and the screen the customer came from. Do not send secrets or device identifiers.

## Listen For Handoff

Use `onHandoff` if your app should show a native banner when a human takes over.

```html theme={"dark"}
<script>
  initOpenScript({
    token: '<WIDGET_TOKEN>',
    inline: true,
    isOpen: true,
    onHandoff: (payload) => {
      window.ReactNativeWebView?.postMessage(
        JSON.stringify({
          type: 'opencx.handoff',
          summary: payload.summary,
        }),
      );
    },
  });
</script>
```

## Mobile Checklist

| Check                   | Why it matters                                              |
| ----------------------- | ----------------------------------------------------------- |
| `inline: true`          | Makes the widget feel like the screen, not a website popup. |
| `isOpen: true`          | Opens chat immediately.                                     |
| `router.chatScreenOnly` | Skips the website-style session browser.                    |
| Verified `user.token`   | Keeps signed-in customers tied to the right contact.        |
| Server-side API key     | Keeps your OpenCX credentials out of the app bundle.        |

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Install Widget" icon="plug" href="/widget/install-widget">
    Web, React, and headless install paths.
  </Card>

  <Card title="Authentication" icon="shield-check" href="/widget/authentication">
    Verified contact tokens and history access.
  </Card>

  <Card title="Configuration" icon="gear" href="/widget/configuration">
    Inline mode, routing, theme, and context options.
  </Card>

  <Card title="Headless" icon="code" href="/widget/custom-components-headless">
    Build custom rendering when WebView is not enough.
  </Card>
</CardGroup>
