Skip to main content
RapidDev - Software Development Agency
\n```\n\nThe value after `key=` is your Web Widget key. Copy it and keep it handy — this is the only credential you need for anonymous chat. It is a public key (similar to an analytics tracking ID) and is safe to embed directly in your FlutterFlow Custom Widget parameters. Do not confuse it with the JWT shared secret, which appears under a different settings tab and must stay server-side."},{"@type":"HowToStep","position":2,"name":"Build an HTML wrapper page that hosts the Zendesk Web Widget snippet","text":"The Zendesk Web Widget is a JavaScript-based component. To display it inside a Flutter app, you need a small HTML page that loads the widget script. You'll host this HTML in a way the WebView widget can load it — the simplest approach is to encode it as a data URI string directly inside your Custom Widget Dart code, which requires no external hosting.\n\nCreate the following HTML content (you'll paste it as a Dart string literal in the next step). Replace YOUR_KEY_HERE with the Web Widget key you copied:\n\n```html\n\n\n\n \n \n \n\n\n \n\n\n```\n\nFor authenticated chat, you'll add a second script block after the snippet that calls `zE('messenger', 'loginUser', function(callback) { callback(JWT_TOKEN); });` where JWT_TOKEN is the token you'll pass into the widget as a parameter. Keep the HTML minimal — a heavy page slows widget load. If you prefer external hosting, upload the page to Firebase Hosting or any static host and note its URL; the WebView will load that URL instead of the inline data URI. Either approach works; inline is easier for getting started and avoids CORS issues."},{"@type":"HowToStep","position":3,"name":"Create a WebView Custom Widget in FlutterFlow using webview_flutter","text":"In your FlutterFlow project, open the left navigation panel and click Custom Code (the angle-brackets icon). Click the + Add button and select Widget from the dropdown. Name the widget something clear like ZendeskChatWidget. In the widget editor, you'll see a Dart code area.\n\nFirst, add the webview_flutter dependency: in the Dependencies field at the top of the Custom Code editor, type webview_flutter and select the latest stable version (e.g., webview_flutter: 4.7.0 — check pub.dev for the current version). FlutterFlow will add it to your project's pubspec.yaml automatically.\n\nNext, define a widget parameter: click the + Add Parameter button and add a String parameter named widgetKey with no default (the user will pass the Web Widget key here). If you plan to support authenticated chat, add a second String parameter named jwtToken with a default of an empty string.\n\nPaste the following Dart code into the widget editor:\n\nFor the widget dimensions, set Width to double.infinity (or use a percent-width) and Height to at least 600 so the chat bubble has room to expand. Save the widget. Now place it on your Support screen: open the screen in the canvas, click the + Add Widget button, find ZendeskChatWidget under Custom Widgets, drag it onto the screen, and in the Properties panel on the right, paste your Web Widget key into the widgetKey parameter field. Leave jwtToken empty for anonymous chat.\n\nIMPORTANT: This Custom Widget will NOT render in FlutterFlow's web Test mode (the 'Run' button in the browser). You must run it on a connected device or emulator. Go to the top-right dropdown, select Run on Device / Emulator, and choose your connected iOS or Android device. The webview_flutter package requires a real platform runtime."},{"@type":"HowToStep","position":4,"name":"Set up a Firebase Cloud Function to generate JWTs for authenticated visitors (optional but recommended)","text":"If your FlutterFlow app has logged-in users and you want Zendesk agents to see who they're chatting with (their name, email, user ID), you need Visitor Authentication. Zendesk validates identity using a JWT signed with your account's shared secret. The shared secret is a private credential — putting it inside your Flutter app would let anyone reverse-engineer it and impersonate any user in Zendesk. The correct pattern is to generate the JWT server-side.\n\nIn the Firebase Console, open your project and navigate to Functions. Create a new function (or use an existing Cloud Function project). Deploy the following Node.js function, replacing YOUR_ZENDESK_SHARED_SECRET with the value from your Zendesk Admin Center → Security → End-users → Visitor Authentication → Shared Secret:\n\nThe function accepts a POST request with the authenticated user's details, signs the JWT, and returns it. In FlutterFlow, create an API Call that POSTs to this Cloud Function URL. The call should send the current user's name and email (which you can pull from your Supabase/Firebase Auth session). Store the returned JWT string in an App State variable, then pass it as the jwtToken parameter to your ZendeskChatWidget.\n\nWith a valid JWT passed in, the chat widget will call `zE('messenger', 'loginUser', ...)` on load, and Zendesk agents will see the user's identity in their Agent Workspace sidebar. Users get conversation continuity — their chat history persists across sessions. For anonymous users (not logged in), leave jwtToken as an empty string and the widget works without authentication."},{"@type":"HowToStep","position":5,"name":"Place the widget on your Support screen and test on a device","text":"With the Custom Widget created and your parameters configured, open the screen in FlutterFlow where you want the chat to appear — typically a dedicated 'Support' or 'Help' screen. In the widget tree, scroll to the bottom of the Add Widget panel and find Custom Widgets. Drag ZendeskChatWidget onto the screen canvas.\n\nIn the Properties panel on the right, fill in the widgetKey field with your Web Widget key (the public key from Zendesk Admin Center). If you built the JWT flow in Step 4, bind the jwtToken field to your App State variable that holds the token. Set the widget's height to at least 500-600 logical pixels so the chat bubble and the expanded conversation window both have room to render.\n\nFor a better UX, consider wrapping the widget in a full-screen modal or a bottom sheet rather than embedding it in a scrollable list. The webview_flutter widget and scroll views can conflict — the webview should receive touch events uninterrupted.\n\nNow test: FlutterFlow's browser-based Test mode will show a blank area or an error where the WebView should be. This is expected — webview_flutter requires native platform support. Instead, connect a physical iOS or Android device via USB or use Android Studio's emulator. In FlutterFlow's top-right corner, click the device dropdown and select your device, then click Run. Wait for the build to complete (a few minutes for the first run). When the app opens on the device, navigate to your Support screen. The Zendesk chat bubble should appear in the bottom-right corner. Tap it to open the chat window and send a test message. Confirm the message appears in your Zendesk Agent Workspace."}]}

Zendesk Chat

Connect FlutterFlow to Zendesk Chat (now Zendesk Messaging) by embedding the Zendesk Web Widget inside a WebView Custom Widget using the webview_flutter package. Pass your public Web Widget key as a widget parameter. For authenticated sessions, generate a JWT server-side in a Firebase Cloud Function — never put the JWT shared secret inside your app.

What you'll learn

  • How to enable Zendesk Messaging and copy the Web Widget key from Admin Center
  • How to build an HTML wrapper page that hosts the Zendesk Web Widget snippet
  • How to create a webview_flutter Custom Widget in FlutterFlow that loads that page
  • How to generate a visitor-authentication JWT in a Firebase Cloud Function
  • Why the WebView Custom Widget won't appear in web Test mode and how to test on a device
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate16 min read45 minutesCommunicationLast updated July 2026RapidDev Engineering Team
TL;DR

Connect FlutterFlow to Zendesk Chat (now Zendesk Messaging) by embedding the Zendesk Web Widget inside a WebView Custom Widget using the webview_flutter package. Pass your public Web Widget key as a widget parameter. For authenticated sessions, generate a JWT server-side in a Firebase Cloud Function — never put the JWT shared secret inside your app.

Quick facts about this guide
FactValue
ToolZendesk Chat
CategoryCommunication
MethodCustom Widget
DifficultyIntermediate
Time required45 minutes
Last updatedJuly 2026

Adding Live Chat to Your FlutterFlow App with Zendesk Messaging

Zendesk Chat was rebranded as Zendesk Messaging and folded into the Agent Workspace — meaning all live-chat, bot, and AI-agent features now flow through one unified product. For a FlutterFlow app, the practical path to embedding that chat experience is the Zendesk Web Widget: a JavaScript snippet that renders the familiar chat bubble on any web surface. Because FlutterFlow compiles to Flutter (a native client app), and the Zendesk native mobile SDK is not packaged for FlutterFlow's Custom Widget system, you bridge the gap using the webview_flutter package to host a tiny HTML page that runs the widget snippet.

The Web Widget key that identifies your Zendesk account is a public credential — analogous to a Google Maps API key — and it is safe to include in your widget parameters. Pricing sits on Zendesk Suite plans starting around $55 per agent per month (check the Zendesk website for current pricing), and all plans that include Messaging give you access to the Web Widget. The main feature gate is authenticated chat: tying a conversation to a specific logged-in user requires a JWT signed with your account's shared secret. That secret is not public, so you must generate the token server-side (Firebase Cloud Function) and pass only the resulting token string to the widget.

The integration unlocks customer support inside your FlutterFlow app without building a custom chat UI from scratch. Your support agents work in the Zendesk Agent Workspace as usual — they never need to know the front-end is Flutter. Keep in mind that push notifications for agent replies and deep-linking the chat widget require Zendesk's native mobile SDK, which is beyond what FlutterFlow's Custom Widget system can add without full code export.

Integration method

Custom Widget

FlutterFlow cannot embed the Zendesk native mobile SDK directly. Instead, you wrap the Zendesk Web Widget (a JavaScript snippet) inside an HTML page and load that page through a webview_flutter Custom Widget. The Web Widget key is public and safe to include in the widget parameter. For authenticated visitors — tying the chat session to a logged-in user — you generate a JWT in a Firebase Cloud Function using your Zendesk shared secret, then feed that token into the widget; the shared secret never leaves the server.

Prerequisites

  • A Zendesk account with a Suite plan that includes Messaging (not just Talk/Email)
  • A FlutterFlow project targeting iOS, Android, or both (web builds will not show the Custom Widget in Test mode)
  • A Firebase project set up and linked to your FlutterFlow app (needed for the optional JWT Cloud Function)
  • Basic familiarity with FlutterFlow's Custom Code panel
  • Your Zendesk subdomain (e.g., yourcompany.zendesk.com) noted and ready

Step-by-step guide

1

Enable Messaging and copy your Web Widget key in Zendesk Admin Center

Log in to your Zendesk account and navigate to Admin Center (the gear icon in the bottom-left sidebar, or go to yourcompany.zendesk.com/admin). In the left navigation, find the Channels section and click Messaging. If Messaging is not yet active, follow the activation flow — it may require you to switch on the feature under Account settings first. Once Messaging is enabled, click Web Widget in the left sub-menu under Channels. If you don't have a Web Widget yet, click Create Widget. After creation (or if one already exists), click the widget to open its settings. Scroll down to find the Installation section — you'll see a code snippet that looks like: ```html <script id="ze-snippet" src="https://static.zdassets.com/ekr/snippet.js?key=YOUR_KEY_HERE"></script> ``` The value after `key=` is your Web Widget key. Copy it and keep it handy — this is the only credential you need for anonymous chat. It is a public key (similar to an analytics tracking ID) and is safe to embed directly in your FlutterFlow Custom Widget parameters. Do not confuse it with the JWT shared secret, which appears under a different settings tab and must stay server-side.

Pro tip: If you see 'Guide' or 'Support' channel options instead of 'Messaging', your account may still be on Classic Chat. Look for a 'Try Messaging' banner or contact Zendesk support to upgrade — the Web Widget with Messaging is only available on Messaging-enabled accounts.

Expected result: You have a Web Widget key string (format: a UUID-like string) copied to your clipboard and the Zendesk Messaging channel is active on your account.

2

Build an HTML wrapper page that hosts the Zendesk Web Widget snippet

The Zendesk Web Widget is a JavaScript-based component. To display it inside a Flutter app, you need a small HTML page that loads the widget script. You'll host this HTML in a way the WebView widget can load it — the simplest approach is to encode it as a data URI string directly inside your Custom Widget Dart code, which requires no external hosting. Create the following HTML content (you'll paste it as a Dart string literal in the next step). Replace YOUR_KEY_HERE with the Web Widget key you copied: ```html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> body { margin: 0; background: transparent; } </style> </head> <body> <script id="ze-snippet" src="https://static.zdassets.com/ekr/snippet.js?key=YOUR_KEY_HERE"> </script> </body> </html> ``` For authenticated chat, you'll add a second script block after the snippet that calls `zE('messenger', 'loginUser', function(callback) { callback(JWT_TOKEN); });` where JWT_TOKEN is the token you'll pass into the widget as a parameter. Keep the HTML minimal — a heavy page slows widget load. If you prefer external hosting, upload the page to Firebase Hosting or any static host and note its URL; the WebView will load that URL instead of the inline data URI. Either approach works; inline is easier for getting started and avoids CORS issues.

zendesk_widget.html
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1">
6 <style>body { margin: 0; background: transparent; }</style>
7</head>
8<body>
9 <script id="ze-snippet"
10 src="https://static.zdassets.com/ekr/snippet.js?key=YOUR_KEY_HERE">
11 </script>
12 <!-- Optional: authenticate the user -->
13 <script>
14 window.onload = function() {
15 if (typeof JWT_TOKEN !== 'undefined' && JWT_TOKEN) {
16 zE('messenger', 'loginUser', function(callback) {
17 callback(JWT_TOKEN);
18 });
19 }
20 };
21 </script>
22</body>
23</html>

Pro tip: Test your HTML page in a regular browser first — navigate to it and confirm the Zendesk chat bubble appears in the bottom-right corner. This confirms your Web Widget key is valid before you debug inside Flutter.

Expected result: You have an HTML page (or HTML string) that shows the Zendesk chat bubble when loaded in a browser.

3

Create a WebView Custom Widget in FlutterFlow using webview_flutter

In your FlutterFlow project, open the left navigation panel and click Custom Code (the angle-brackets icon). Click the + Add button and select Widget from the dropdown. Name the widget something clear like ZendeskChatWidget. In the widget editor, you'll see a Dart code area. First, add the webview_flutter dependency: in the Dependencies field at the top of the Custom Code editor, type webview_flutter and select the latest stable version (e.g., webview_flutter: 4.7.0 — check pub.dev for the current version). FlutterFlow will add it to your project's pubspec.yaml automatically. Next, define a widget parameter: click the + Add Parameter button and add a String parameter named widgetKey with no default (the user will pass the Web Widget key here). If you plan to support authenticated chat, add a second String parameter named jwtToken with a default of an empty string. Paste the following Dart code into the widget editor: For the widget dimensions, set Width to double.infinity (or use a percent-width) and Height to at least 600 so the chat bubble has room to expand. Save the widget. Now place it on your Support screen: open the screen in the canvas, click the + Add Widget button, find ZendeskChatWidget under Custom Widgets, drag it onto the screen, and in the Properties panel on the right, paste your Web Widget key into the widgetKey parameter field. Leave jwtToken empty for anonymous chat. IMPORTANT: This Custom Widget will NOT render in FlutterFlow's web Test mode (the 'Run' button in the browser). You must run it on a connected device or emulator. Go to the top-right dropdown, select Run on Device / Emulator, and choose your connected iOS or Android device. The webview_flutter package requires a real platform runtime.

zendesk_chat_widget.dart
1import 'package:flutter/material.dart';
2import 'package:webview_flutter/webview_flutter.dart';
3
4class ZendeskChatWidget extends StatefulWidget {
5 final String widgetKey;
6 final String jwtToken;
7 final double width;
8 final double height;
9
10 const ZendeskChatWidget({
11 Key? key,
12 required this.widgetKey,
13 this.jwtToken = '',
14 required this.width,
15 required this.height,
16 }) : super(key: key);
17
18 @override
19 State<ZendeskChatWidget> createState() => _ZendeskChatWidgetState();
20}
21
22class _ZendeskChatWidgetState extends State<ZendeskChatWidget> {
23 late final WebViewController _controller;
24
25 String get _htmlContent => '''
26<!DOCTYPE html>
27<html>
28<head>
29 <meta charset="utf-8">
30 <meta name="viewport" content="width=device-width, initial-scale=1">
31 <style>body { margin: 0; background: transparent; }</style>
32</head>
33<body>
34 <script id="ze-snippet"
35 src="https://static.zdassets.com/ekr/snippet.js?key=${widget.widgetKey}">
36 </script>
37 <script>
38 window.onload = function() {
39 var jwt = '${widget.jwtToken}';
40 if (jwt && jwt.length > 0) {
41 zE('messenger', 'loginUser', function(callback) { callback(jwt); });
42 }
43 };
44 </script>
45</body>
46</html>''';
47
48 @override
49 void initState() {
50 super.initState();
51 _controller = WebViewController()
52 ..setJavaScriptMode(JavaScriptMode.unrestricted)
53 ..setBackgroundColor(Colors.transparent)
54 ..loadHtmlString(_htmlContent);
55 }
56
57 @override
58 Widget build(BuildContext context) {
59 return SizedBox(
60 width: widget.width,
61 height: widget.height,
62 child: WebViewWidget(controller: _controller),
63 );
64 }
65}

Pro tip: If you need camera or file-attachment features inside the chat widget, add camera and storage permissions in FlutterFlow under Settings & Integrations → Permissions. On iOS, set NSCameraUsageDescription and NSPhotoLibraryUsageDescription. On Android, add READ_EXTERNAL_STORAGE and CAMERA. Without these, the widget's attachment button silently fails.

Expected result: The ZendeskChatWidget appears in your Custom Widgets list in FlutterFlow, and when you run the app on a physical device, the Zendesk chat bubble appears in the bottom-right corner of the Support screen.

4

Set up a Firebase Cloud Function to generate JWTs for authenticated visitors (optional but recommended)

If your FlutterFlow app has logged-in users and you want Zendesk agents to see who they're chatting with (their name, email, user ID), you need Visitor Authentication. Zendesk validates identity using a JWT signed with your account's shared secret. The shared secret is a private credential — putting it inside your Flutter app would let anyone reverse-engineer it and impersonate any user in Zendesk. The correct pattern is to generate the JWT server-side. In the Firebase Console, open your project and navigate to Functions. Create a new function (or use an existing Cloud Function project). Deploy the following Node.js function, replacing YOUR_ZENDESK_SHARED_SECRET with the value from your Zendesk Admin Center → Security → End-users → Visitor Authentication → Shared Secret: The function accepts a POST request with the authenticated user's details, signs the JWT, and returns it. In FlutterFlow, create an API Call that POSTs to this Cloud Function URL. The call should send the current user's name and email (which you can pull from your Supabase/Firebase Auth session). Store the returned JWT string in an App State variable, then pass it as the jwtToken parameter to your ZendeskChatWidget. With a valid JWT passed in, the chat widget will call `zE('messenger', 'loginUser', ...)` on load, and Zendesk agents will see the user's identity in their Agent Workspace sidebar. Users get conversation continuity — their chat history persists across sessions. For anonymous users (not logged in), leave jwtToken as an empty string and the widget works without authentication.

index.js
1// Firebase Cloud Function: generateZendeskJWT
2// Deploy with: firebase deploy --only functions
3const functions = require('firebase-functions');
4const cors = require('cors')({ origin: true });
5const jwt = require('jsonwebtoken');
6
7const ZENDESK_SHARED_SECRET = functions.config().zendesk.shared_secret;
8// Set with: firebase functions:config:set zendesk.shared_secret="YOUR_SECRET"
9
10exports.generateZendeskJWT = functions.https.onRequest((req, res) => {
11 cors(req, res, () => {
12 if (req.method !== 'POST') {
13 return res.status(405).send('Method Not Allowed');
14 }
15
16 const { name, email, external_id } = req.body;
17 if (!name || !email) {
18 return res.status(400).json({ error: 'name and email are required' });
19 }
20
21 const payload = {
22 name: name,
23 email: email,
24 external_id: external_id || email,
25 iat: Math.floor(Date.now() / 1000),
26 exp: Math.floor(Date.now() / 1000) + 3600 // 1 hour
27 };
28
29 const token = jwt.sign(payload, ZENDESK_SHARED_SECRET, {
30 algorithm: 'HS256'
31 });
32
33 return res.status(200).json({ token });
34 });
35});

Pro tip: In the Cloud Function project directory, run 'npm install jsonwebtoken cors' before deploying. If you skip installing the jsonwebtoken package, the function will crash on startup with a 'Cannot find module' error.

Expected result: Your Cloud Function is deployed and returns a valid JWT when called with a user's name and email. In FlutterFlow, the jwtToken App State variable is populated after login and passed to the ZendeskChatWidget, causing authenticated users to be identified in Zendesk's Agent Workspace.

5

Place the widget on your Support screen and test on a device

With the Custom Widget created and your parameters configured, open the screen in FlutterFlow where you want the chat to appear — typically a dedicated 'Support' or 'Help' screen. In the widget tree, scroll to the bottom of the Add Widget panel and find Custom Widgets. Drag ZendeskChatWidget onto the screen canvas. In the Properties panel on the right, fill in the widgetKey field with your Web Widget key (the public key from Zendesk Admin Center). If you built the JWT flow in Step 4, bind the jwtToken field to your App State variable that holds the token. Set the widget's height to at least 500-600 logical pixels so the chat bubble and the expanded conversation window both have room to render. For a better UX, consider wrapping the widget in a full-screen modal or a bottom sheet rather than embedding it in a scrollable list. The webview_flutter widget and scroll views can conflict — the webview should receive touch events uninterrupted. Now test: FlutterFlow's browser-based Test mode will show a blank area or an error where the WebView should be. This is expected — webview_flutter requires native platform support. Instead, connect a physical iOS or Android device via USB or use Android Studio's emulator. In FlutterFlow's top-right corner, click the device dropdown and select your device, then click Run. Wait for the build to complete (a few minutes for the first run). When the app opens on the device, navigate to your Support screen. The Zendesk chat bubble should appear in the bottom-right corner. Tap it to open the chat window and send a test message. Confirm the message appears in your Zendesk Agent Workspace.

Pro tip: If the chat bubble appears but is very small or clipped, increase the Custom Widget's height parameter in FlutterFlow's Properties panel. The Zendesk widget expands upward from the bubble, so it needs at least 500px of vertical space to render the conversation window properly.

Expected result: Running the app on a physical device shows the Zendesk chat bubble on the Support screen. Tapping the bubble opens the chat window. A test message sent from the app appears in the Zendesk Agent Workspace, confirming end-to-end connectivity.

Common use cases

E-commerce app with embedded order-support chat

A FlutterFlow shopping app places the Zendesk Messaging widget on the Order Detail screen. When a customer taps 'Get Help', the widget opens pre-populated with their order context via an authenticated JWT, so agents immediately see who they're talking to and which order is in question.

FlutterFlow Prompt

Add a Support button on the Order Detail screen that opens a Zendesk live-chat window pre-filled with the current user's email and order ID.

Copy this prompt to try it in FlutterFlow

SaaS onboarding app with contextual help

A B2B SaaS onboarding app shows a persistent chat bubble on every screen. New users can ask setup questions in real time. The FlutterFlow app passes the user's account tier to the widget so Zendesk can route enterprise customers to a dedicated support queue.

FlutterFlow Prompt

Show a Zendesk chat bubble on every screen of my onboarding app. When the user is logged in, pass their email and plan type to the chat widget automatically.

Copy this prompt to try it in FlutterFlow

Marketplace app with seller dispute resolution

A two-sided marketplace built in FlutterFlow lets sellers open a Zendesk chat session when a buyer raises a dispute. The widget is placed on the Dispute screen and the seller's store name is pre-filled as an authenticated identity so agents can pull up the seller account instantly.

FlutterFlow Prompt

Add a Zendesk chat widget to the Dispute screen that identifies the logged-in seller by their email and store name.

Copy this prompt to try it in FlutterFlow

Troubleshooting

The chat widget area is completely blank in FlutterFlow's Test mode (browser preview)

Cause: webview_flutter Custom Widgets do not render in FlutterFlow's web-based Test/Run mode. The package requires a native iOS or Android runtime to function.

Solution: Connect a physical device or launch an Android emulator. In the FlutterFlow top-right corner, switch from 'Test' to your device in the Run dropdown and click Run. The widget will appear correctly on the native device.

Chat bubble does not appear on the device — the webview area is white or blank

Cause: The Web Widget key may be incorrect, or the HTML page failed to load the Zendesk snippet due to a network error. JavaScript errors in the snippet can also silently prevent the bubble from rendering.

Solution: Double-check that the widgetKey parameter contains the exact UUID-format key from Zendesk Admin Center (no extra spaces). Enable JavaScript debugging in the WebViewController by calling `setOnConsoleMessage` in the Dart code to surface JS errors. Also verify the device has internet connectivity — the snippet loads from static.zdassets.com.

401 Unauthorized when calling the JWT Cloud Function, or JWT rejected by Zendesk ('Visitor Authentication Failed')

Cause: Either the JWT shared secret in the Cloud Function does not match the one in Zendesk Admin Center, or the JWT payload is missing required fields (name, email, exp, iat).

Solution: In Zendesk Admin Center → Security → End-users → Visitor Authentication, copy the shared secret again and re-set it in Firebase Functions config. Ensure the JWT payload includes name, email, exp, and iat. Use jwt.io to decode and inspect the token before passing it to the widget.

File attachment or camera in the chat widget fails silently on iOS or Android

Cause: The Flutter app does not have the required platform permissions declared, so the OS blocks the WebView from accessing the camera or file system.

Solution: In FlutterFlow, go to Settings & Integrations → Permissions. On iOS, add NSCameraUsageDescription and NSPhotoLibraryUsageDescription with descriptive messages. On Android, add CAMERA and READ_EXTERNAL_STORAGE. Rebuild and redeploy to the device.

Best practices

  • Never embed your Zendesk JWT shared secret in the Flutter app — always generate tokens in a Firebase Cloud Function and pass only the resulting token string to the widget.
  • Test the WebView widget exclusively on a physical device or emulator, not in FlutterFlow's browser Test mode, which does not support webview_flutter.
  • Load the HTML page inline as a Dart string (using loadHtmlString) rather than fetching from an external URL — this eliminates one network request and avoids CORS issues on web builds.
  • Set the WebView widget's height to at least 500 logical pixels to ensure the full chat window can render without clipping when it expands from the bubble.
  • Refresh the JWT token before it expires (Zendesk JWTs have a configurable expiry; issue a new one on each app launch or session start) to prevent users from being de-authenticated mid-session.
  • Declare all required permissions (camera, storage) in FlutterFlow's Permissions settings before your first production build — adding them afterward requires a re-submission to the app stores.
  • Use Zendesk's Messaging channel (not the legacy Chat channel) — the legacy Chat product is being sunset and the Web Widget with Messaging is the supported path going forward.

Alternatives

Frequently asked questions

Can I use the Zendesk native mobile Chat SDK in FlutterFlow instead of the WebView approach?

Not without exporting your FlutterFlow project as Flutter code. The Zendesk iOS/Android Chat SDK must be added as a native dependency (CocoaPods on iOS, Gradle on Android) and wrapped in a Flutter plugin, which requires editing platform-level project files. FlutterFlow's Custom Widget system only supports pub.dev packages, not native SDKs registered outside pub.dev. If you need the full native SDK, export your project and continue development in a standard Flutter IDE.

Will the Zendesk chat bubble appear on Flutter web builds?

The webview_flutter package supports web builds, but behavior can be inconsistent — some browser environments block the inline HTML approach. For Flutter web specifically, it is often simpler to inject the Zendesk snippet directly into the host HTML file (web/index.html) in your exported Flutter project, bypassing the Custom Widget entirely. That approach is not configurable inside FlutterFlow without code export.

Do I need a paid Zendesk plan to use the Messaging Web Widget?

Yes. Zendesk Messaging is included in Suite plans (Suite Team and above). The free Zendesk trial gives access to Messaging, but you will need an active paid plan to serve real customer conversations. The Web Widget key and the Conversations API are part of the same Suite entitlement.

Can my app receive push notifications when an agent replies to a chat?

Not through the WebView widget approach alone. Push notifications for Zendesk Messaging require integrating the Zendesk mobile push SDK (iOS/Android native), which is not available as a pub.dev package. For now, users must keep the Support screen open to see new agent replies in real time. If push notifications are essential, consider RapidDev's team for a full code-export implementation — free scoping call at rapidevelopers.com/contact.

How do I customize the appearance of the Zendesk chat bubble (colors, position)?

Appearance customization is done inside Zendesk Admin Center → Channels → Web Widget → Appearance. You can change the theme color, launcher label, and position there. These settings are applied server-side by Zendesk and reflected in the widget automatically — no changes to your Flutter code are needed.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire FlutterFlow integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.