Skip to main content
The recommended way to integrate Molin AI in your iOS app is by rendering our widget inside a WKWebView component. See the full working example on GitHub: molin-ai/molin-ai-ios-example.

Basic setup

Create an HTML file that loads the widget and displays the chat component fullscreen:
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover" />
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      html,
      body {
        height: 100%;
        width: 100%;
        overflow: hidden;
        background: #fdfdfd;
      }
      molin-shop-ai-chat {
        display: block;
        width: 100%;
        height: 100%;
      }
    </style>
    <script type="module" src="https://widget.molin.ai/shop-ai.js"></script>
  </head>
  <body>
    <molin-shop-ai-chat show-close widget="YOUR_WIDGET_ID"></molin-shop-ai-chat>
  </body>
</html>
Replace YOUR_WIDGET_ID with your actual widget ID from the Molin dashboard. The show-close attribute is optional. It renders a close button (✕) in the chat header, which is useful when the widget is displayed fullscreen in a webview. You can omit it if your app has its own navigation to dismiss the chat.

Handling the close button

When the user taps the close button, the <molin-shop-ai-chat> element fires a molin-shop-ai-chat:close-click event. Navigate to a custom molin:// URL to tell the native side to go back:
<script type="module">
  document.addEventListener('molin-shop-ai-chat:close-click', () => {
    window.location.href = 'molin://close';
  });
</script>
On the Swift side, intercept the molin:// scheme in a WKNavigationDelegate:
import WebKit

class Coordinator: NSObject, WKNavigationDelegate {
    var onClose: () -> Void

    init(onClose: @escaping () -> Void) {
        self.onClose = onClose
    }

    func webView(
        _ webView: WKWebView,
        decidePolicyFor navigationAction: WKNavigationAction,
        decisionHandler: @escaping (WKNavigationActionPolicy) -> Void
    ) {
        if navigationAction.request.url?.scheme == "molin" {
            if navigationAction.request.url?.host == "close" {
                DispatchQueue.main.async { self.onClose() }
            }
            decisionHandler(.cancel)
            return
        }
        decisionHandler(.allow)
    }
}

// when creating the WKWebView:
let coordinator = Coordinator(onClose: { /* navigate back */ })
webView.navigationDelegate = coordinator