Copy your widget key
Dashboard → Widget Settings → Embed. Note your widget key (wk_…).
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.
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.
Dashboard → Widget Settings → Embed. Note your widget key (wk_…).
Widget Settings → Allowed Domains → add app:com.example.app (your real bundle ID).
Use the URL below with platform and app_id query params. The dashboard Embed tab generates this for each platform.
Paste the platform snippet (Android, iOS, React Native, or Flutter) into your app. Enable JavaScript and DOM storage.
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).
Load this URL in your WebView. Replace YOUR_WIDGET_KEY and com.example.app with your values from Widget Settings.
https://wiretalk.tech/popout/YOUR_WIDGET_KEY?platform=android&app_id=com.example.app&locale=en&tab=chat
| Query param | Required | Description |
|---|---|---|
platform | Yes | android, ios, react-native, flutter, capacitor, or cordova |
app_id | Yes | Your app bundle ID (e.g. com.example.app) |
locale | No | Widget language — default en |
tab | No | Initial tab: chat or home |
visitor_uid | No | Resume an existing visitor session (UUID) |
visitor_name, visitor_email, visitor_phone | No | Pre-fill identity for logged-in app users |
app_version | No | Sent to visitor analytics |
Copy platform-specific WebView code from Dashboard → Widget Settings → Embed → Platform (Website, Android, iOS, React Native, Flutter).
| Setting | Android | iOS |
|---|---|---|
| JavaScript | javaScriptEnabled = true | Default on WKWebView |
| DOM storage | domStorageEnabled = true | Default enabled |
| Media (calls / voice notes) | mediaPlaybackRequiresUserGesture = false | allowsInlineMediaPlayback |
| Camera / mic permissions | Declare in AndroidManifest.xml | Add 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.
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.
Enable JavaScript, DOM storage, and a WiretalkAndroid JavaScript interface to receive bridge events.
<!-- 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.
<!-- 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.
}
}
*/
// 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 — 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);
}
}
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 type | When | Payload |
|---|---|---|
widget:ready | After init completes | visitor_uid, conversation_id, platform, app_id |
unread:count | Unread agent messages change | count, conversation_id |
message:received | New agent message arrives | message_id, body, conversation_id |
widget:state | Panel opens or closes | open, tab, conversation_id |
{
"type": "unread:count",
"count": 3,
"conversation_id": 42,
"platform": "android"
}
Post messages from native code to open the chat, update visitor identity, or control the widget:
| Type | Effect |
|---|---|
widget:open | Open chat panel (optional tab: chat or home) |
widget:close | Close chat panel |
widget:toggle | Toggle open/closed |
visitor:update | Update visitor name, email, phone |
storage:set / storage:remove | Sync visitor_uid across app restarts |
{
"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.
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.
Text chat, attachments, pre-chat forms, tickets, KB search, appointments, account login OTP, voice notes, voice/video calls (HTTPS + permissions required).
Push notifications (FCM/APNs), background reconnect, and secure storage of visitor_uid. Wiretalk provides bridge events; your app decides how to surface them.