W Wiretalk Docs
Developer documentation

Mobile Apps (WebView)

Add Wiretalk live chat to Android, iOS, React Native, and Flutter apps without a native SDK. Load the popout URL in a WebView with a JavaScript bridge for unread counts and visitor identity.

No native SDK required. Wiretalk is a browser-first chat widget. Android, iOS, React Native, Flutter, Capacitor, and Cordova apps load the full chat UI in a WebView — the same widget your website uses, with a JavaScript bridge for unread counts and visitor identity.

There is no separate Wiretalk mobile SDK to install. Your app hosts a WebView pointed at the Wiretalk popout URL. All chat features — messaging, attachments, voice notes, tickets, appointments, and voice/video calls — run inside the WebView.

Setup checklist

1

Copy your widget key

Dashboard → Widget Settings → Embed. Note your widget key (wk_…).

2

Register the app bundle ID

Widget Settings → Allowed Domains → add app:com.example.app (your real bundle ID).

3

Build the popout URL

Use the URL below with platform and app_id query params. The dashboard Embed tab generates this for each platform.

4

Load in a WebView

Paste the platform snippet (Android, iOS, React Native, or Flutter) into your app. Enable JavaScript and DOM storage.

5

Wire the JavaScript bridge

Listen for unread:count and message:received to update tab badges or trigger local push notifications.

Test without building an app: open Preview mobile ↗ from Widget Settings (replace the widget key and bundle ID first).

Architecture

Popout URL

Load this URL in your WebView. Replace YOUR_WIDGET_KEY and com.example.app with your values from Widget Settings.

popout-url.txt
https://wiretalk.tech/popout/YOUR_WIDGET_KEY?platform=android&app_id=com.example.app&locale=en&tab=chat
Query paramRequiredDescription
platformYesandroid, ios, react-native, flutter, capacitor, or cordova
app_idYesYour app bundle ID (e.g. com.example.app)
localeNoWidget language — default en
tabNoInitial tab: chat or home
visitor_uidNoResume an existing visitor session (UUID)
visitor_name, visitor_email, visitor_phoneNoPre-fill identity for logged-in app users
app_versionNoSent to visitor analytics

Copy platform-specific WebView code from Dashboard → Widget Settings → Embed → Platform (Website, Android, iOS, React Native, Flutter).

WebView requirements

SettingAndroidiOS
JavaScriptjavaScriptEnabled = trueDefault on WKWebView
DOM storagedomStorageEnabled = trueDefault enabled
Media (calls / voice notes)mediaPlaybackRequiresUserGesture = falseallowsInlineMediaPlayback
Camera / mic permissionsDeclare in AndroidManifest.xmlAdd usage strings in Info.plist
Safe area (notch)Popout mode applies env(safe-area-inset-*) padding automatically

Voice and video calls require HTTPS and a TURN server for reliable connectivity on mobile networks. See Voice & video on mobile WebView.

Register your app bundle ID

Mobile apps do not use a website hostname. Instead, add your bundle ID to Allowed Domains using the app: prefix:

app:com.example.app

Widget init sends platform and app_id instead of a page URL. Requests are rejected if the bundle ID is not on your allowlist. See the domain restrictions guide.

Platform snippets

Enable JavaScript, DOM storage, and a WiretalkAndroid JavaScript interface to receive bridge events.

WiretalkChatActivity.kt
<!-- Wiretalk — Android (Kotlin WebView) -->
<!-- Add app:com.example.app to Allowed Domains -->
/*
class WiretalkChatActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val webView = WebView(this)
        setContentView(webView)
        webView.settings.javaScriptEnabled = true
        webView.settings.domStorageEnabled = true
        webView.settings.mediaPlaybackRequiresUserGesture = false
        webView.webChromeClient = WebChromeClient()
        webView.addJavascriptInterface(object {
            @JavascriptInterface
            fun postMessage(payload: String) {
                runOnUiThread { handleWiretalkEvent(payload) }
            }
        }, "WiretalkAndroid")
        webView.loadUrl("https://wiretalk.tech/popout/YOUR_WIDGET_KEY?locale=en&tab=chat&platform=android&app_id=com.example.app")
    }
}
*/

Use WKWebView with a script message handler named wiretalk.

WiretalkChatController.swift
<!-- Wiretalk — iOS (Swift WKWebView) -->
<!-- Add app:com.example.app to Allowed Domains -->
/*
import WebKit

final class WiretalkChatController: UIViewController, WKScriptMessageHandler {
    private lazy var webView: WKWebView = {
        let config = WKWebViewConfiguration()
        config.userContentController.add(self, name: "wiretalk")
        config.defaultWebpagePreferences.allowsContentJavaScript = true
        return WKWebView(frame: .zero, configuration: config)
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view = webView
        webView.load(URLRequest(url: URL(string: "https://wiretalk.tech/popout/YOUR_WIDGET_KEY?locale=en&tab=chat&platform=ios&app_id=com.example.app")!))
    }

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        guard message.name == "wiretalk" else { return }
        // Handle unread:count, message:received, etc.
    }
}
*/
WiretalkChat.tsx
// Wiretalk — React Native (react-native-webview)
// npm install react-native-webview
// Add app:com.example.app to Allowed Domains

import WebView from 'react-native-webview';

export function WiretalkChat({ onUnreadCount }) {
  return (
    <WebView
      source={{ uri: 'https://wiretalk.tech/popout/YOUR_WIDGET_KEY?locale=en&tab=chat&platform=react-native&app_id=com.example.app' }}
      javaScriptEnabled
      domStorageEnabled
      mediaPlaybackRequiresUserAction={false}
      allowsInlineMediaPlayback
      onMessage={(event) => {
        const msg = JSON.parse(event.nativeEvent.data);
        if (msg.type === 'unread:count') onUnreadCount?.(msg.count);
      }}
    />
  );
}
wiretalk_chat_page.dart
// Wiretalk — Flutter (webview_flutter)
// Add app:com.example.app to Allowed Domains

import 'package:webview_flutter/webview_flutter.dart';

class WiretalkChatPage extends StatefulWidget {
  @override
  State<WiretalkChatPage> createState() => _WiretalkChatPageState();
}

class _WiretalkChatPageState extends State<WiretalkChatPage> {
  late final controller = WebViewController()
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    ..loadRequest(Uri.parse('https://wiretalk.tech/popout/YOUR_WIDGET_KEY?locale=en&tab=chat&platform=flutter&app_id=com.example.app'));

  @override
  Widget build(BuildContext context) {
    return WebViewWidget(controller: controller);
  }
}

JavaScript bridge

When loaded inside a native WebView, the widget posts JSON messages your app can listen for. Use these to update tab badges, show local notifications, or sync visitor identity.

Event typeWhenPayload
widget:readyAfter init completesvisitor_uid, conversation_id, platform, app_id
unread:countUnread agent messages changecount, conversation_id
message:receivedNew agent message arrivesmessage_id, body, conversation_id
widget:statePanel opens or closesopen, tab, conversation_id
Incoming bridge message (JSON)
{
  "type": "unread:count",
  "count": 3,
  "conversation_id": 42,
  "platform": "android"
}

Send commands to the widget

Post messages from native code to open the chat, update visitor identity, or control the widget:

TypeEffect
widget:openOpen chat panel (optional tab: chat or home)
widget:closeClose chat panel
widget:toggleToggle open/closed
visitor:updateUpdate visitor name, email, phone
storage:set / storage:removeSync visitor_uid across app restarts
visitor:update example
{
  "wiretalk": true,
  "type": "visitor:update",
  "visitor": {
    "name": "Jane Doe",
    "email": "jane@example.com",
    "phone": "9876543210"
  }
}

Wrap outbound messages with "wiretalk": true when posting from native code into the WebView. On Android, use WiretalkAndroid.postMessage(JSON.stringify(payload)). On iOS, use webkit.messageHandlers.wiretalk.postMessage(payload). React Native uses WebView.onMessage.

Logged-in app users

Pass visitor details via URL params when opening the WebView, or send a visitor:update bridge message after login:

https://wiretalk.tech/popout/YOUR_WIDGET_KEY?platform=ios&app_id=com.example.app&visitor_name=Jane&visitor_email=jane@example.com

See also: Pre-fill visitor identity for website embeds.

Feature parity

Works in WebView

Text chat, attachments, pre-chat forms, tickets, KB search, appointments, account login OTP, voice notes, voice/video calls (HTTPS + permissions required).

Native app responsibilities

Push notifications (FCM/APNs), background reconnect, and secure storage of visitor_uid. Wiretalk provides bridge events; your app decides how to surface them.

Next steps