Flutter WebView Bridge
This guide explains how to use WebEngage's JavaScript Bridge to enable SDK tracking from within a WebView in your Flutter applications. By using this bridge, web content inside a WebView can communicate directly with the Flutter app to trigger events like login, logout, tracking, and screen views
How It Works
The bridge acts as a communication layer between your web content and the native Flutter SDK:
Trigger: JavaScript within the WebView calls standard WebEngage methods such as webengage.user.login() or webengage.track().
Forward: The bridge intercepts these calls and forwards the data to the native Flutter layer.
Handle: The WebEngage Flutter SDK receives these forwarded events and processes them accordingly.
Prerequisites :
- webengage_flutter : 1.7.0 or Above
Supported WebView Plugins :
- webview_flutter
- flutter_inappwebview
Setup Instructions
Step 1 : Include the JS Bridge in Your Web Project
Create a file named webengage_flutter_bridge.js in your web project and add the code to define the bridge handlers
/**
* Checks if `webview_flutter` bridge is available.
* @returns {boolean} True if the webview_flutter channel is available.
*/
function isWebViewFlutterAvailable() {
return (
typeof window.webengage_flutter !== "undefined" &&
typeof window.webengage_flutter.postMessage === "function"
);
}
/**
* Checks if `flutter_inappwebview` bridge is available.
* @returns {boolean} True if the inappwebview handler is available.
*/
function isInAppWebViewAvailable() {
return typeof window.flutter_inappwebview !== "undefined";
}
// ====================================
// Constants
// ====================================
const CHANNEL_NAME = "webengage_flutter";
const METHOD_LOGIN = "login";
const METHOD_LOGOUT = "logout";
const METHOD_SET_ATTRIBUTE = "setAttribute";
const METHOD_SCREEN = "screen";
const METHOD_TRACK_EVENT = "trackEvent";
const OBJECT_TYPE = "[object Object]";
// ====================================
// Initialization for `webview_flutter`
// ====================================
/**
* Initializes the WebEngage bridge for `webview_flutter`.
* Sets up function bindings and message handler.
*/
function initializeWebViewFlutterBridge() {
const sendToWebViewFlutter = function (method, ...args) {
const payload = JSON.stringify({ method, args });
window.webengage_flutter.postMessage(payload);
};
initWebEngageBridge(sendToWebViewFlutter);
}
// ====================================
// Initialization for `flutter_inappwebview`
// ====================================
/**
* Initializes the WebEngage bridge for `flutter_inappwebview`.
* Sets up handler callbacks for native communication.
*/
function initializeInAppWebViewBridge() {
const sendToInAppWebView = function (method, ...args) {
window.flutter_inappwebview.callHandler(CHANNEL_NAME, method, ...args);
};
initWebEngageBridge(sendToInAppWebView);
}
// ====================================
// Common Bridge Logic
// ====================================
/**
* Initializes the core WebEngage bridge by attaching WebEngage methods
* and routing method calls to the native layer using the provided sender.
*
* @param {function} sendFunction - Function to dispatch method + args to native side.
*/
function initWebEngageBridge(sendFunction) {
const type = Object.prototype.toString;
// Setup global namespace if not already defined
const we = window.webengage || (window.webengage = {});
const user = (we.user = we.user || {});
/**
* Logs in or identifies the user by user ID.
* @param {string} id - Unique user ID.
*/
user.login = user.identify = function (id) {
sendFunction(METHOD_LOGIN, id);
};
/**
* Logs out the current user.
*/
user.logout = function () {
sendFunction(METHOD_LOGOUT, {});
};
/**
* Sets user attributes (single or multiple).
* @param {string|object} name - Attribute name or object of key-value pairs.
* @param {*} [value] - Value if name is a string.
*/
user.setAttribute = function (name, value) {
let attr = {};
if (type.call(name) === OBJECT_TYPE) {
attr = name;
} else {
attr[name] = value;
}
sendFunction(METHOD_SET_ATTRIBUTE, attr);
};
/**
* Tracks screen navigation within the app.
* @param {string|object} name - Screen name or data.
* @param {object} [data] - Optional metadata.
*/
we.screen = function (name, data) {
if (arguments.length === 1 && type.call(name) === OBJECT_TYPE) {
data = name;
name = null;
}
sendFunction(
METHOD_SCREEN,
name || null,
type.call(data) === OBJECT_TYPE ? data : null
);
};
/**
* Tracks a custom event with optional metadata.
* @param {string} name - Event name.
* @param {object} [data] - Optional metadata.
*/
we.track = function (name, data) {
sendFunction(
METHOD_TRACK_EVENT,
name,
type.call(data) === OBJECT_TYPE ? data : null
);
};
console.log("WebEngage Flutter bridge initialized");
}
Step 2 : Embed the Script in HTML
Ensure you embed the webengage_flutter_bridge.js before the main WebEngage SDK (webengage.js):
<!-- MUST BE INCLUDED FIRST -->
<script src="webengage_flutter_bridge.js"></script>
<!-- Then include the main WebEngage SDK -->
<script src="webengage.js"></script>You must embed the
webengage_flutter_bridge.jsbefore the main WebEngage SDK (webengage.js). This allows the bridge to override the default SDK behavior for WebViews.
Step 3 : Update Instructions for webengage.js
webengage.jsTo integrate WebEngage correctly with Flutter WebViews, update your webengage.js as shown below.
Implementation by Plugin
Choose the plugin you are currently using in your Flutter project for the setup instructions.
webview_flutter :
if (isWebViewFlutterAvailable()) {
console.log("Detected webview_flutter. Initializing bridge...");
initializeWebViewFlutterBridge();
} else {
// fallback to default Web SDK initialization
}
flutter_inappwebview :
if (isInAppWebViewAvailable()) {
console.log("Detected flutter_inappwebview. Waiting for platformReady...");
window.addEventListener("flutterInAppWebViewPlatformReady", initializeInAppWebViewBridge);
}else{
// fallback to default Web SDK initialization
}Final Version of webengage.js (with WebView detection)
var webengage;
! function (w, e, b, n, g) {
function o(e, t) {
e[t[t.length - 1]] = function () {
r.__queue.push([t.join("."), arguments])
}
}
var i, s, r = w[b],
z = " ",
l = "init options track screen onReady".split(z),
a = "feedback survey notification".split(z),
c = "options render clear abort".split(z),
p = "Open Close Submit Complete View Click".split(z),
u = "identify login logout setAttribute".split(z);
if (!r || !r.__v) {
for (w[b] = r = {
__queue: [],
__v: "6.0",
user: {}
}, i = 0; i < l.length; i++) o(r, [l[i]]);
for (i = 0; i < a.length; i++) {
for (r[a[i]] = {}, s = 0; s < c.length; s++) o(r[a[i]], [a[i], c[s]]);
for (s = 0; s < p.length; s++) o(r[a[i]], [a[i], "on" + p[s]])
}
for (i = 0; i < u.length; i++) o(r.user, ["user", u[i]])
}
}(window, document, "webengage");
if (isInAppWebViewAvailable()) {
console.log("Detected flutter_inappwebview. Waiting for platformReady...");
window.addEventListener("flutterInAppWebViewPlatformReady", initializeInAppWebViewBridge);
} else {
console.log("Flutter WebView not detected. Loading WebEngage Web SDK...");
setTimeout(function () {
var f = document.createElement("script"),
d = document.getElementById("_webengage_script_tag");
f.type = "text/javascript",
f.async = !0,
f.src = ("https:" == window.location.protocol ? "https://ssl.widgets.webengage.com" : "http://cdn.widgets.webengage.com") + "/js/webengage-min-v-6.0.js",
d.parentNode.insertBefore(f, d)
});
webengage.init("YOUR_LICENSE_CODE");
}
Data Center Setup Reminder
This example uses the Global Data Center (ssl.widgets.webengage.com).
If your account is on a different data center, please update the script URL accordingly.Refer to official documentation for the correct Data Center URL: WebEngage Web SDK Docs
Step 4 : Flutter Integration Code
Configure your Flutter app to listen for messages from the bridge. This requires webengage_flutter version 1.7.0 or higher
Implementation by Plugin
Choose the plugin you are currently using in your Flutter project for the setup instructions.
webview_flutter :
WebViewWidget(
controller: WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadRequest(Uri.parse(webUrl))
..addJavaScriptChannel(WebEngageJSBridge.jsChannelName,
onMessageReceived: (JavaScriptMessage message) {
WebEngageJSBridge.handleWebViewFlutterMessage(message.message);
}));flutter_inappwebview :
InAppWebView(
initialUrlRequest: URLRequest(
url: WebUri(webUrl),
),
onWebViewCreated: (InAppWebViewController controller) async {
controller.addJavaScriptHandler(
handlerName: WebEngageJSBridge.jsChannelName,
callback: (args) {
WebEngageJSBridge.handleInAppWebViewMessage(args);
});
});WebEngageJSBridge is a Dart helper class used to handle messages from JavaScript and forward them to the WebEngage SDK.
It is available starting from version 1.7.0 of thewebengage_flutterpackage.
User Attributes
List of System User Attributes Defined by WebEngage (Supported from version 2.0.1)
| Name | Type | Description |
|---|---|---|
we_first_name | String | User's first name |
we_last_name | String | User's last name |
we_email | String | User's email address |
we_birth_date | String | User's birth date in yyyy-mm-dd format |
we_phone | String | User's phone number in E.164 format. Example: +551155256325 |
we_gender | String | User's gender. Values can only be male, female, or other |
we_company | String | User's company |
we_hashed_email | String | Encrypted email address |
we_hashed_phone | String | Encrypted phone number |
we_push_opt_in | Boolean | If set to false, the user will not receive push notifications on any of their devices |
we_sms_opt_in | Boolean | If set to false, the user will be excluded from promotional SMS campaigns |
we_email_opt_in | Boolean | If set to false, the user will be excluded from promotional email campaigns |
Updated about 4 hours ago