Flutter Widget Integration
A complete guide to embedding and configuring a Flutter web widget inside Zoho CRM using the Zoho Embedded App SDK.
1. Overview
This document describes how to add the Zoho Embedded App SDK script to an existing Flutter Web project so that the Flutter widget runs inside a Zoho CRM panel and communicates correctly with the Zoho JS SDK.
What the Integration Does
Loads the Zoho Embedded App SDK from the Zoho CDN.
Initialises the SDK on page load so the widget can call Zoho CRM APIs.
Automatically resizes the widget panel to fill the available space in Zoho CRM.
Bootstraps the compiled Flutter web app through the standard
flutter_bootstrap.jsentry point.
Prerequisites
Requirement | Details |
|---|---|
Flutter SDK | 3.x or later with web support enabled |
Zoho CRM account | Developer or above plan with Widget Builder access |
Zoho Embedded App SDK | Loaded via CDN (no local install needed) |
Web server / hosting | Any static host or Zoho Widget deployment target |
2. Project File Structure
The integration targets the index.html file that Flutter generates inside the web/ directory of your project.
my_flutter_app/
web/
index.html <-- Primary file to modify
manifest.json
flutter_bootstrap.js
icons/
lib/
pubspec.yaml
3. Complete index.html
Replace the entire content of web/index.html with the code below. Every section is explained in detail in the following chapter.
<html>
<head>
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="Flutter Zoho Widget">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>flutter_map_web</title>
<link rel="manifest" href="manifest.json">
<style>
html,
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
#flutter_container {
height: 100%;
width: 100%;
}
</style>
<script src="https://live.zwidgets.com/js-sdk/1.2/ZohoEmbededAppSDK.min.js"></script>
</head>
<body>
<div id="flutter_container"></div>
<script>
function resizeWidget() {
if (window.ZOHO && ZOHO.CRM && ZOHO.CRM.UI) {
ZOHO.CRM.UI.Resize({
height: "100%",
width: "100%"
});
}
}
window.addEventListener("load", function () {
if (window.ZOHO) {
ZOHO.embeddedApp.on("PageLoad", function () {
resizeWidget();
});
ZOHO.embeddedApp
.init()
.then(function () {
console.log("Zoho SDK Initialized");
})
.catch(function (error) {
console.error("Zoho SDK Init Failed:", error);
});
}
});
</script>
<script src="flutter_bootstrap.js" async></script>
</body>
</html>
4. Code Explanation
4.1 <head> Section
4.1.1 base href
<base href="$FLUTTER_BASE_HREF">
Flutter replaces the $FLUTTER_BASE_HREF placeholder at build time with the correct sub-path for the deployment. This tag is mandatory for Flutter web asset resolution and must remain exactly as shown.
4.1.2 Viewport Meta Tag
<meta name="viewport" content="width=device-width, initial-scale=1.0">
Ensures the widget renders correctly on both desktop Zoho CRM panels and mobile browsers. Without this, the Flutter canvas may render at the wrong scale inside the CRM panel.
4.1.3 CSS Reset
html, body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
#flutter_container { height: 100%; width: 100%; }
Removes all default browser spacing so the Flutter canvas fills the Zoho CRM panel edge-to-edge. overflow: hidden prevents unwanted scrollbars inside the panel.
4.1.4 Zoho SDK Script
<script src="https://live.zwidgets.com/js-sdk/1.2/ZohoEmbededAppSDK.min.js"></script>
Loads the Zoho Embedded App SDK from the official Zoho CDN. This script must be placed in <head> and loaded before the Zoho initialisation code in <body> runs. It exposes the global ZOHO object used throughout the integration.
NOTE: Do not host this file locally. Zoho requires the CDN version for authentication tokens and API routing to work correctly.
4.2 <body> Section
4.2.1 Flutter Container Div
<div id="flutter_container"></div>
Flutter web renders its canvas into this div. The id must match what flutter_bootstrap.js expects. The CSS defined earlier stretches it to fill the entire viewport.
4.2.2 resizeWidget Helper Function
function resizeWidget() {
if (window.ZOHO && ZOHO.CRM && ZOHO.CRM.UI) {
ZOHO.CRM.UI.Resize({
height: "100%",
width: "100%"
});
}
}
Calls the Zoho CRM UI API to resize the widget panel to 100% of its container. The guard checks that ZOHO.CRM.UI is available before calling it, which prevents console errors when the page is opened outside of Zoho (e.g. during local development).
4.2.3 SDK Initialisation Block
window.addEventListener("load", function () {
if (window.ZOHO) {
ZOHO.embeddedApp.on("PageLoad", function () {
resizeWidget();
});
ZOHO.embeddedApp
.init()
.then(function () {
console.log("Zoho SDK Initialized");
})
.catch(function (error) {
console.error("Zoho SDK Init Failed:", error);
});
}
});
This is the core SDK bootstrap. Each part explained:
Code | Purpose |
|---|---|
| Waits until all resources (including the Zoho SDK script) are fully loaded before running. |
| Safety check. If the page is opened outside Zoho (e.g. localhost), the SDK script will not inject the |
| Registers a callback that fires each time Zoho CRM loads or reloads the widget panel. The resize call is placed here so panel dimensions are set on every load. |
| Authenticates the widget with Zoho CRM, fetches the CRM context (logged-in user, module, record), and resolves the promise. All subsequent |
| Called when |
| Called when |
4.2.4 Flutter Bootstrap Script
<script src="flutter_bootstrap.js" async></script>
Loads the Flutter web entry point. The async attribute allows the browser to continue parsing the HTML and running the Zoho initialisation block in parallel, which reduces widget startup time. Flutter will render into #flutter_container once its own initialisation is complete.
5. Build & Deployment
5.1 Build the Flutter Web App
# Standard release build
flutter build web
# If deployed to a sub-path, set the base href manually
flutter build web --base-href /your-sub-path/
The build output is placed in build/web/. The web/index.html you edited is copied into this output directory with $FLUTTER_BASE_HREF replaced automatically.
5.2 Upload to Zoho CRM Widget Builder
Open Zoho CRM and go to Settings > Developer Space > Widgets.
Click Create Widget and choose the widget type (Detail View, List View, etc.).
Upload the entire contents of
build/web/as a ZIP file.Set the Widget URL to the
index.htmlat the root of the uploaded bundle.Save and preview the widget inside Zoho CRM.
NOTE: If you update the Flutter app, rebuild with
flutter build weband re-upload the newbuild/web/ZIP. The Zoho SDK script URL does not need to change.
6. Local Development & Testing
6.1 Running Outside Zoho
When you run flutter run -d chrome, the ZOHO global will not exist. The if (window.ZOHO) guard means the SDK block is silently skipped, so the Flutter app still loads and renders normally.
To simulate the Zoho environment locally, you can stub the ZOHO global in a separate dev-only script:
// dev_stub.js — do NOT include in production build
window.ZOHO = {
embeddedApp: {
on: function(event, cb) { if (event === "PageLoad") cb(); },
init: function() { return Promise.resolve(); }
},
CRM: {
UI: { Resize: function(o) { console.log("Resize called", o); } }
}
};
7. Calling Zoho CRM APIs from Flutter
Once the SDK is initialised you can call Zoho CRM APIs from JavaScript and pass data to Flutter using postMessage or dart:js interop.
7.1 Example: Get Current Record
// After ZOHO.embeddedApp.init() resolves:
ZOHO.CRM.API.getRecord({ Entity: "Leads", RecordID: recordId })
.then(function(data) {
// Forward data to Flutter via a custom DOM event
window.dispatchEvent(
new CustomEvent("zoho-data", { detail: data })
);
});
7.2 Receiving Data in Flutter (dart:js_interop)
import 'dart:js_interop';
void listenForZohoData() {
window.addEventListener('zoho-data', (event) {
final detail = (event as CustomEvent).detail;
// Use detail in your Flutter widget state
}.toJS);
}
8. Troubleshooting
Symptom | Solution |
|---|---|
Widget shows blank panel in Zoho | Check browser console for errors. Ensure |
| Verify the widget is opened inside Zoho CRM, not directly in a browser. Check that the Zoho SDK CDN URL is accessible. |
Panel does not fill the Zoho frame | Confirm the CSS reset ( |
| You are viewing |
Flutter assets return 404 | Rebuild with the correct |
9. Quick Reference
Item | Value |
|---|---|
Zoho SDK CDN URL |
|
SDK global object |
|
Init method |
|
Page load event |
|
Resize API |
|
Flutter container id |
|
Flutter entry script |
|
Build output directory |
|
Build command |
|
End of Document