Connect FlutterFlow to LivePerson by embedding the LivePerson Web Messaging tag in a Custom Widget WebView — the fastest path requires only your public LivePerson Site ID, no backend. For REST access to Conversational Cloud APIs (agent queues, conversation history, analytics), you must first discover your regional base URL via the domain-discovery endpoint and then proxy all OAuth app-key calls through a Firebase Cloud Function.
| Fact | Value |
|---|---|
| Tool | LivePerson |
| Category | Communication |
| Method | Custom Widget |
| Difficulty | Advanced |
| Time required | 60 minutes |
| Last updated | July 2026 |
Add LivePerson Messaging to Your FlutterFlow App
LivePerson Conversational Cloud is an enterprise-grade messaging platform primarily designed for large contact-center deployments. It supports web chat, in-app messaging, and AI-powered bots, and it charges on a per-seat, enterprise contract basis — there is no public self-serve pricing or trial tier (contact LivePerson sales for current pricing). For a FlutterFlow developer, there are two realistic integration paths: a fast WebView embed and a deeper REST API integration.
The fast path is a Custom Widget containing a webview_flutter WebView that loads a tiny HTML page carrying the LivePerson Web Messaging JavaScript snippet. You supply your organization's LivePerson Site ID (account number) in the snippet — this ID appears on every website that uses LivePerson, so it is not a secret and is safe to include in the widget. The chat bubble renders inside the WebView, giving users access to live agents and bots configured in your LivePerson account. This works on both web builds and iOS/Android builds (inside the native WebView). The trade-off is that it is not a native Flutter UI — it is a browser-rendered chat window inside a container.
The REST API path accesses the Conversational Cloud Platform API for tasks like reading conversation history, checking agent availability, pulling analytics, or triggering automated engagement flows. This path is significantly more complex: LivePerson's base URLs are region-specific and NOT fixed in advance. You must first call the domain-discovery endpoint at https://api.liveperson.net/api/account/{siteid}/service/{service}/baseURI.json to resolve which regional host serves your account, then use that resolved URL as the base URL for your actual API calls. Authentication uses OAuth 2.0 app keys that must never appear in compiled Dart. Route all Conversational Cloud REST calls through a Firebase Cloud Function that holds the secrets and caches the resolved domain-discovery results.
Integration method
The primary FlutterFlow integration embeds LivePerson's Web Messaging JavaScript snippet inside a Custom Widget backed by a `webview_flutter` WebView. Your public LivePerson Site ID is included in the HTML — it is safe client-side because it appears on every public website using LivePerson. For REST access to Conversational Cloud APIs, a second path uses a FlutterFlow API Call targeting a Firebase Cloud Function that holds the OAuth app secret, calls the domain-discovery endpoint to resolve the regional base URL, then forwards requests to the LivePerson API.
Prerequisites
- A LivePerson Conversational Cloud account with an assigned Site ID (account number) — contact LivePerson sales if you do not have one
- For REST API access: OAuth app credentials (app key and app secret) from your LivePerson account admin console
- A Firebase project with Blaze plan enabled for outbound HTTP Cloud Functions
- A FlutterFlow project on a plan that supports Custom Code (Custom Widgets and Custom Actions)
- Basic Dart familiarity for building the Custom Widget (the code is minimal — mostly standard WebView configuration)
Step-by-step guide
Find your LivePerson Site ID and set up the Web Messaging snippet
Log in to the LivePerson Conversational Cloud admin console (your organization's LivePerson instance). Navigate to Campaigns → Data Sources, or look in the 'Engagement Window' or 'Web Tag' configuration section — the exact path varies by your LivePerson account version and plan. Your Site ID (also called Account Number) is a numeric string like `12345678`. It appears in the JavaScript snippet that LivePerson provides for website embedding. Copy the full Web Messaging JavaScript snippet — it looks like `window.lpTag = window.lpTag || {}; ... (function(d) { var s = d.createElement('script'); s.src = 'https://lptag.liveperson.net/tag/tag.js?site=12345678'; ... })(document);`. This is the code that will go inside the HTML string your Custom Widget loads in a WebView. The Site ID is public — it appears on every page of every website that has LivePerson installed, so there is no security concern with including it in your FlutterFlow widget. You do NOT need OAuth credentials for the WebView path; those are only needed if you also want to call Conversational Cloud REST APIs.
Pro tip: If you cannot find the Web Messaging snippet in the LivePerson console, search for 'Web Tag' or ask your LivePerson account manager. Some enterprise accounts use customized deployment methods.
Expected result: You have your LivePerson Site ID (a numeric string) and the full Web Messaging JavaScript snippet text copied and ready.
Build a Custom Widget with a WebView that loads the LivePerson chat snippet
In FlutterFlow, open the left navigation and click Custom Code. Click + Add and select Widget. Name the widget 'LivePersonChatWidget'. In the Dependencies field, add `webview_flutter` — this is the official Flutter package for embedding a WebView. FlutterFlow will add it to the project's pubspec.yaml automatically when you add it here. In the widget code editor, write a StatefulWidget that creates a WebViewController, loads an HTML string containing your LivePerson snippet, and renders it in a WebView. The HTML string must be a complete document with a `<head>`, `<body>`, and the LivePerson script tag. Set `javascript: JavascriptMode.unrestricted` on the WebView — this is essential; without JavaScript enabled, the LivePerson script never runs and the chat bubble never appears. Also set `debuggingEnabled: true` in development to see JavaScript errors in the console. For iOS, WebView JavaScript is enabled by default in `webview_flutter`; for Android, also set `domStorageEnabled: true` on the `WebViewAndroidController`. Add two widget parameters (named `siteId` and `heightPx`) so you can configure the Site ID and height from the FlutterFlow canvas without editing code. Note: Custom Widgets do not render in the FlutterFlow canvas/preview — you must run a web or device build (use Run button → Chrome for web builds, or connect a device for iOS/Android) to see the chat bubble appear. The canvas shows a grey placeholder.
1// custom_widget.dart — LivePersonChatWidget2import 'package:flutter/material.dart';3import 'package:webview_flutter/webview_flutter.dart';45class LivePersonChatWidget extends StatefulWidget {6 const LivePersonChatWidget({7 super.key,8 required this.width,9 required this.height,10 this.siteId = 'YOUR_SITE_ID', // set via widget parameter11 });1213 final double width;14 final double height;15 final String siteId;1617 @override18 State<LivePersonChatWidget> createState() => _LivePersonChatWidgetState();19}2021class _LivePersonChatWidgetState extends State<LivePersonChatWidget> {22 late final WebViewController _controller;2324 @override25 void initState() {26 super.initState();27 _controller = WebViewController()28 ..setJavaScriptMode(JavaScriptMode.unrestricted) // REQUIRED29 ..loadHtmlString(_buildHtml(widget.siteId));30 }3132 String _buildHtml(String siteId) {33 return '''34<!DOCTYPE html>35<html>36 <head><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>37 <body style="margin:0;padding:0;background:transparent;">38 <!-- LivePerson Web Messaging Tag -->39 <script type="text/javascript">40 window.lpTag = window.lpTag || {};41 window.lpTag.site = "$siteId";42 window.lpTag.section = [];43 (function(d) {44 var s = d.createElement('script');45 s.setAttribute('async', '');46 s.setAttribute('type', 'text/javascript');47 s.src = 'https://lptag.liveperson.net/tag/tag.js?site=$siteId';48 d.getElementsByTagName('head')[0].appendChild(s);49 })(document);50 </script>51 </body>52</html>53''';54 }5556 @override57 Widget build(BuildContext context) {58 return SizedBox(59 width: widget.width,60 height: widget.height,61 child: WebViewWidget(controller: _controller),62 );63 }64}Pro tip: Set the widget height to fill the screen (e.g., `MediaQuery.of(context).size.height`) for a full-page chat experience, or to a fixed height like 400 for a panel at the bottom of a screen.
Expected result: The custom widget code compiles without errors in FlutterFlow. When you run a web or device build, the LivePerson chat bubble appears in the widget area.
Place the widget on a Support screen and test on a real build
In the FlutterFlow page editor, create a new page called 'Support'. Open the Add Elements panel (click the + icon in the left navigation toolbar, or press A). Scroll to Custom Widgets at the bottom of the list and drag 'LivePersonChatWidget' onto the page. In the right Properties panel, set the widget's `siteId` parameter to your LivePerson Site ID string (e.g., `12345678`). Set width to Fill Container (or a fixed pixel width) and height to Fill Container or a fixed value. The canvas will show a grey placeholder — this is normal for WebView-based Custom Widgets. To actually test it, click the Run button in the top-right toolbar and select 'Run in Chrome' for a web build. The browser opens a preview of your app. Navigate to the Support screen. After the page loads, the LivePerson script runs inside the WebView and the chat bubble appears in the bottom-right corner (or wherever your LivePerson account has configured it to appear). If the bubble does not appear: check the browser developer console for JavaScript errors, verify that JavaScript mode is set to unrestricted in the widget code, and confirm that the Site ID matches your LivePerson account exactly. For iOS/Android builds, use Test Mode or a local device build — the process is the same, but the WebView renders natively using the device's embedded browser engine.
Pro tip: If the chat bubble appears but does not respond to clicks on iOS, check that `navigationDelegate` is set to allow all navigation in the WebViewController — some LivePerson interactions open new tabs or popups.
Expected result: Running the app in a web or device build shows the LivePerson chat bubble on the Support screen. Clicking the bubble opens the live chat window and connects to the configured LivePerson agent or bot.
Discover your regional LivePerson API base URL for REST access
If you need to call Conversational Cloud REST APIs (conversation history, agent queues, analytics, proactive engagements), the first hurdle is that LivePerson's base URLs are NOT fixed. Every LivePerson account is hosted in a specific AWS region, and the domain-discovery endpoint tells you which regional host to use. The discovery URL is: `https://api.liveperson.net/api/account/{siteid}/service/{service}/baseURI.json?version=1.0`. Replace `{siteid}` with your numeric Site ID and `{service}` with the service name you need — common services include `agentVep` (Agent Virtual Experience — conversations), `engHistDomain` (Engagement History), `leDataReporting` (analytics), and `msgHist` (Messaging History). This returns a JSON response like `{ "baseURI": "va.enghist.liveperson.net", "service": "engHistDomain" }`. The `baseURI` value is the host to use for that service's API calls. This discovery step should run once at app startup (or cached in your Cloud Function) rather than on every request. For your Firebase Cloud Function, call the discovery endpoint for each service you need, cache the resolved hosts, and use them in subsequent API calls. The discovery endpoint itself is public (no auth required) and can be called directly by FlutterFlow as an API Call.
1// Firebase Cloud Function: discover LivePerson domains and cache them2// Call once at startup; cache in memory or Firestore3async function discoverDomain(siteId, service) {4 const url = `https://api.liveperson.net/api/account/${siteId}/service/${service}/baseURI.json?version=1.0`;5 const response = await fetch(url);6 const data = await response.json();7 return data.baseURI; // e.g., 'va.enghist.liveperson.net'8}910// Usage in the Cloud Function before making any API call:11const engHistHost = await discoverDomain(siteId, 'engHistDomain');12const apiUrl = `https://${engHistHost}/interaction_history/api/account/${siteId}/interactions/search`;13// Then call apiUrl with OAuth app credentials...Pro tip: Cache the discovered domain URIs — they rarely change for a given account, but the discovery endpoint may have rate limits. Store them in a Firestore document and refresh only if a subsequent API call returns a 301 or 401 that suggests the host changed.
Expected result: You have the regional base URI for each LivePerson service you need (e.g., `va.enghist.liveperson.net` for Engagement History). These values are stored in your Cloud Function's cache and ready to use in API calls.
Deploy a Firebase Cloud Function to proxy Conversational Cloud REST calls
LivePerson Conversational Cloud REST APIs use OAuth 2.0 app credentials — an app key and app secret that act as client credentials. These must NEVER appear in a FlutterFlow API Call header or Dart widget because they grant access to your entire contact-center account. Deploy a Firebase Cloud Function that holds `LIVEPERSON_APP_KEY` and `LIVEPERSON_APP_SECRET` as environment variables. The function accepts a request from FlutterFlow with a `service` parameter (e.g., `engHistDomain`) and the API path, runs domain discovery (from cache), builds the OAuth signature or bearer token per the LivePerson API's OAuth 1.0a-style signing (verify the specific auth scheme required for your plan in LivePerson docs — some plans use OAuth 2.0 bearer, others use OAuth 1.0a request signing), and proxies the request. Return the API response JSON back to FlutterFlow. In FlutterFlow, create an API Group pointing to your Cloud Function base URL, add API Calls for each LivePerson feature (conversations list, engagement history, etc.), and parse the responses with JSON Paths to bind to your widgets. Add CORS headers to the Cloud Function for web builds. If you'd rather skip this complex proxy setup, RapidDev's team builds FlutterFlow integrations like this every week — free scoping call at rapidevelopers.com/contact.
1// functions/index.js — LivePerson Conversational Cloud proxy (simplified)2const functions = require('firebase-functions');3const fetch = require('node-fetch');45// Domain cache (in production, use Firestore for persistence across cold starts)6const domainCache = {};78async function getBaseDomain(siteId, service) {9 const key = `${siteId}_${service}`;10 if (!domainCache[key]) {11 const url = `https://api.liveperson.net/api/account/${siteId}/service/${service}/baseURI.json?version=1.0`;12 const res = await fetch(url);13 const data = await res.json();14 domainCache[key] = data.baseURI;15 }16 return domainCache[key];17}1819exports.livepersonProxy = functions.https.onRequest(async (req, res) => {20 res.set('Access-Control-Allow-Origin', '*');21 res.set('Access-Control-Allow-Headers', 'Content-Type');22 if (req.method === 'OPTIONS') { res.status(204).send(''); return; }2324 const siteId = process.env.LIVEPERSON_SITE_ID;25 // NOTE: OAuth signing varies by LP plan — check your LP docs for exact auth scheme26 // This example uses a simplified Bearer approach for illustration27 const appKey = process.env.LIVEPERSON_APP_KEY;28 const appSecret = process.env.LIVEPERSON_APP_SECRET;2930 const { service, path } = req.body;31 if (!service || !path) {32 res.status(400).json({ error: 'Missing service or path' });33 return;34 }3536 const baseHost = await getBaseDomain(siteId, service);37 const apiUrl = `https://${baseHost}${path}`;3839 // Implement OAuth signing here per LivePerson documentation for your specific plan40 const response = await fetch(apiUrl, {41 method: req.method,42 headers: {43 'Authorization': `Bearer ${appKey}`, // Replace with proper OAuth implementation44 'Content-Type': 'application/json'45 },46 body: req.method !== 'GET' ? JSON.stringify(req.body) : undefined47 });4849 const data = await response.json();50 res.status(200).json(data);51});Pro tip: LivePerson's Conversational Cloud uses different auth schemes across its APIs — verify whether your specific plan requires OAuth 1.0a request signing (older APIs) or OAuth 2.0 Bearer tokens (newer APIs) in the LivePerson developer portal before implementing the Cloud Function auth logic.
Expected result: The Cloud Function is deployed and responds correctly to requests from FlutterFlow. API calls to Conversational Cloud services (engagement history, queue data) return valid JSON that you can parse with JSON Paths in FlutterFlow.
Common use cases
Customer support app with a LivePerson chat bubble for live agent access
A FlutterFlow customer app includes a 'Support' screen with a Custom Widget that embeds the LivePerson Web Messaging snippet. When users tap the chat bubble, they connect to a live agent (or a bot for initial triage) configured in the LivePerson Conversational Cloud console. No backend is needed — just the public Site ID in the HTML snippet. The widget works on iOS, Android, and web builds.
Add a 'Contact Support' screen with a full-screen WebView that loads the LivePerson chat widget using our Site ID. Show a loading indicator until the chat bubble appears.
Copy this prompt to try it in FlutterFlow
Agent dashboard app that reads conversation data from the Conversational Cloud API
A FlutterFlow internal app for contact-center supervisors that shows active conversations, agent queue lengths, and CSAT metrics by calling the Conversational Cloud Platform API through a Cloud Function proxy. The app displays conversation counts in a summary card and lists recent closed conversations in a ScrollableList. The Cloud Function resolves the regional API domain on startup and caches it to avoid calling domain-discovery on every request.
Build a supervisor dashboard screen showing: total active conversations (from the queue API), average handle time (from analytics API), and a list of recent conversations with customer name and status.
Copy this prompt to try it in FlutterFlow
E-commerce app that triggers a proactive LivePerson engagement when a user idles on checkout
A FlutterFlow shopping app monitors how long a user stays on the checkout screen. After 45 seconds without completing a purchase, the app calls a Cloud Function that uses the LivePerson Engagement API to trigger a proactive chat invitation. The function uses the domain-discovered Engagement History API to log the interaction. The WebView widget at the bottom of the checkout screen becomes visible when the invitation fires.
After 45 seconds on the checkout screen, show the LivePerson chat widget and fire a proactive engagement invitation via the Engagement API. Log the attempt to our Firestore collection.
Copy this prompt to try it in FlutterFlow
Troubleshooting
The LivePerson chat bubble does not appear in the WebView — the widget area is blank or shows a white screen
Cause: The most common cause is that JavaScript is not enabled on the WebViewController. Without `JavaScriptMode.unrestricted`, the LivePerson script tag runs but the dynamic JavaScript never executes, so the chat widget never initializes. A secondary cause is that DOM storage is disabled on Android, which the LivePerson script requires to track sessions.
Solution: In the Custom Widget Dart code, ensure `_controller.setJavaScriptMode(JavaScriptMode.unrestricted)` is called before `loadHtmlString`. On Android WebViews, also enable DOM storage — add a platform-specific setup step or use the newer `webview_flutter` API that enables it by default. Run a web build and open Chrome DevTools Console to see any LivePerson script errors.
1// Correct setup2final controller = WebViewController()3 ..setJavaScriptMode(JavaScriptMode.unrestricted)4 ..loadHtmlString(htmlString);LivePerson REST API calls return 401 Unauthorized or 404 Not Found even though credentials look correct
Cause: Hard-coding a base URL (e.g., `https://api.liveperson.net`) for the actual Conversational Cloud APIs is wrong — that URL is only the domain-discovery endpoint. The actual service endpoints have region-specific hostnames like `va.enghist.liveperson.net`. Using the wrong host returns 401 or 404 that look like auth errors but are actually host mismatch errors.
Solution: Always call the domain-discovery endpoint first: `https://api.liveperson.net/api/account/{siteid}/service/{service}/baseURI.json?version=1.0`. Use the returned `baseURI` as the host for your API calls. Cache the result in your Cloud Function to avoid calling discovery on every request.
The Custom Widget shows a grey box in the FlutterFlow canvas (preview) and never renders the chat widget
Cause: This is expected behavior — Custom Widgets based on WebView (and most `webview_flutter` implementations) do not render in the FlutterFlow visual canvas. The canvas shows a placeholder because it cannot execute native platform code. The widget only works in real builds.
Solution: Use the FlutterFlow 'Run' button → 'Run in Chrome' for a web build test, or connect a physical device for iOS/Android testing. The chat bubble will appear correctly in a real build. This is not a bug — it is a limitation of the FlutterFlow canvas for Custom Widgets.
On iOS, the chat bubble appears but tapping it does nothing, or clicks are not registered
Cause: Some LivePerson chat interactions open links, popups, or navigate to new pages inside the WebView. If the WebViewController's navigation delegate blocks external URLs or new window requests, these interactions silently fail.
Solution: In the WebViewController, set a navigation delegate that allows all navigation types: `..setNavigationDelegate(NavigationDelegate(onNavigationRequest: (NavigationRequest req) => NavigationDecision.navigate))`. This allows the LivePerson widget to open chat windows, links, and confirmation screens inside the WebView.
1_controller = WebViewController()2 ..setJavaScriptMode(JavaScriptMode.unrestricted)3 ..setNavigationDelegate(NavigationDelegate(4 onNavigationRequest: (req) => NavigationDecision.navigate,5 ))6 ..loadHtmlString(_buildHtml(widget.siteId));Best practices
- Use the WebView embed path (Custom Widget) for visitor-facing chat — it is the fastest, most reliable way to get LivePerson working in FlutterFlow without managing OAuth secrets.
- Never hardcode the Conversational Cloud API base URL — always call the domain-discovery endpoint first and use the returned regional host. The wrong host causes 401/404 errors that look like auth failures.
- Proxy all OAuth app credentials (app key, app secret) through a Firebase Cloud Function — never put them in FlutterFlow API Call headers or Dart code, as they grant full access to your LivePerson account.
- Enable JavaScript (`JavaScriptMode.unrestricted`) and DOM storage in the WebViewController — without both, the LivePerson Web Messaging script silently fails to initialize.
- Test Custom Widgets exclusively on real builds (web → Run in Chrome, mobile → device build) — the FlutterFlow canvas does not render WebView-based widgets.
- Cache domain-discovery results in your Cloud Function (or Firestore) to avoid calling the discovery endpoint on every API request — it rarely changes for a given account.
- Set realistic expectations: LivePerson is an enterprise platform with no self-serve sign-up; confirm your account type, plan, and API access before building the integration.
Alternatives
Olark is a much simpler WebView embed with just a public Site ID and no OAuth backend — the right choice if you need basic live chat without enterprise contact-center features.
Zendesk Chat offers a more developer-friendly REST API and a mobile SDK with better documentation than LivePerson; suitable if your team already uses Zendesk Support.
Intercom has an official mobile Flutter SDK and simpler setup than LivePerson's enterprise auth flow; better for product teams who want in-app messaging without a contact-center contract.
Frequently asked questions
Is the LivePerson Site ID safe to include in a Flutter app or widget?
Yes. The LivePerson Site ID (account number) is a public identifier that appears in the JavaScript tag on every website that uses LivePerson — it is not a secret. Including it in your Custom Widget's HTML or as a widget parameter is fine. What must NOT appear client-side are the OAuth app key and app secret used for Conversational Cloud REST API access — those must stay in a Firebase Cloud Function.
Can I use LivePerson's Mobile Messaging SDK in FlutterFlow?
Not easily. LivePerson offers native iOS and Android Mobile Messaging SDKs, but there is no official Flutter package that wraps them. To use these SDKs in FlutterFlow, you would need to write a platform-specific Custom Action using method channels and Dart FFI — this is advanced native plugin work that goes well beyond standard FlutterFlow development. The WebView embed approach described in this guide gives you a working chat experience with far less complexity.
Why does the LivePerson API require domain discovery before every API call?
LivePerson runs its Conversational Cloud services across multiple AWS regions (US, EU, APAC, etc.). Each account is assigned to a region, and the actual API endpoints are region-specific. Rather than publishing a fixed global URL, LivePerson provides a discovery service that maps your account's Site ID to the correct regional hostname for each API service. This means the domain-discovery endpoint is always the first call — you get the correct host, then use it for all subsequent requests. Cache the results to avoid calling discovery repeatedly.
Does the LivePerson WebView widget work on both iOS and Android?
Yes — `webview_flutter` supports iOS (WKWebView), Android (WebView), and web (iframe or HTML element). The LivePerson Web Messaging script is standard JavaScript and works in all three environments as long as JavaScript is enabled and DOM storage is available. On iOS there are no additional Info.plist permissions needed for a basic WebView; on Android no extra AndroidManifest entries are required by default. Test each platform separately, as LivePerson's script behavior can vary slightly between browser engines.
Can FlutterFlow receive incoming LivePerson chat events in real time?
Not natively. LivePerson pushes events (new messages, conversation state changes, agent joins) via server-sent events or webhooks — there is no way for a FlutterFlow app to receive these directly. The WebView embed handles this automatically inside the JavaScript SDK. For REST-based scenarios, the practical approach is to poll Conversational Cloud APIs from a Cloud Function on a schedule and write results to Firestore, which FlutterFlow reads via a Backend Query.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation