Build an AI-powered customer support chatbot using a Cloud Function that calls the OpenAI Chat Completions API with your support knowledge base as a system prompt. Display messages in a reversed ListView with distinct user and bot bubbles. Store conversation history in Firestore and implement a sliding window to control API costs. Add a live agent handoff that escalates the conversation when the bot cannot resolve the issue after three attempts.
Building an AI Customer Support Chatbot in FlutterFlow
An AI chatbot provides instant answers to common questions, reducing support load and improving user experience. This tutorial builds a chatbot powered by the OpenAI Chat Completions API with your business knowledge base as context, a polished chat UI with message bubbles, conversation persistence in Firestore, and a handoff mechanism to escalate to a live agent when the bot reaches its limits.
Prerequisites
- A FlutterFlow project with Firebase authentication enabled
- An OpenAI API key with access to the Chat Completions API
- Cloud Functions enabled on the Firebase Blaze plan
- Firestore database configured in your Firebase project
Step-by-step guide
Set up the Firestore schema for chat sessions and messages
Set up the Firestore schema for chat sessions and messages
Create a `chat_sessions` collection with fields: userId (String), status (String: active/escalated/resolved), createdAt (Timestamp), lastMessageAt (Timestamp), escalatedAt (Timestamp, optional), agentId (String, optional). Add a `messages` subcollection under each session with fields: role (String: user/assistant/system), content (String), timestamp (Timestamp). The role field matches OpenAI's message format directly, making it easy to pass conversation history to the API. Register both collections in FlutterFlow's Data panel.
Expected result: Chat sessions and messages collections are created with roles matching OpenAI's format for seamless API integration.
Build the chat UI with reversed ListView and styled message bubbles
Build the chat UI with reversed ListView and styled message bubbles
Create a ChatBot page. Add a Column filling the full screen. The main area is a ListView bound to a Backend Query on the current session's messages subcollection ordered by timestamp ascending, with the ListView set to reverse: true (this keeps the latest message at the bottom). For each message, use a Conditional layout: if role is 'user', align the Container to the right with a blue background and white text. If role is 'assistant', align left with a grey background and dark text. Add padding, rounded corners (topLeft, topRight, and the opposite bottom corner), and the message text inside. Below the ListView, pin a Row at the bottom with a multiline TextField and a Send IconButton. Add a typing indicator: when waiting for the bot response, show three animated dots in a left-aligned Container.
Expected result: A chat interface with user messages on the right in blue and bot responses on the left in grey, with a text input and send button pinned at the bottom.
Create the Cloud Function that calls OpenAI with your knowledge base
Create the Cloud Function that calls OpenAI with your knowledge base
Create a callable Cloud Function named chatWithBot. It receives the sessionId and the user's message text. The function: (1) reads the last 10 messages from the session's messages subcollection, (2) constructs the OpenAI messages array starting with a system prompt containing your support knowledge base (FAQ answers, policies, product info), (3) appends the conversation history and the new user message, (4) calls the OpenAI Chat Completions API with model 'gpt-4o-mini' (cost-effective for support), (5) saves both the user message and assistant response to the messages subcollection, (6) returns the assistant's response text. Store the OpenAI API key in Firebase Functions config, never in client code.
1const functions = require('firebase-functions');2const admin = require('firebase-admin');3const OpenAI = require('openai');4admin.initializeApp();56const openai = new OpenAI({7 apiKey: functions.config().openai.key,8});910const SYSTEM_PROMPT = `You are a helpful customer support assistant for [YourApp].11Knowledge base:12- Pricing: Free plan includes X. Pro plan is $Y/month.13- Returns: 30-day return policy for unused items.14- Shipping: Standard 5-7 days, Express 2-3 days.15- Account: Users can reset passwords via Settings > Security.16Rules:17- Be concise and friendly.18- If you cannot answer, say "Let me connect you with a support agent."19- Never make up information not in the knowledge base.`;2021exports.chatWithBot = functions.https.onCall(async (data, context) => {22 if (!context.auth) throw new functions.https.HttpsError(23 'unauthenticated', 'Must be logged in');2425 const { sessionId, message } = data;26 const db = admin.firestore();27 const messagesRef = db28 .collection(`chat_sessions/${sessionId}/messages`);2930 // Save user message31 await messagesRef.add({32 role: 'user',33 content: message,34 timestamp: admin.firestore.FieldValue.serverTimestamp(),35 });3637 // Load last 10 messages for context window38 const history = await messagesRef39 .orderBy('timestamp', 'desc').limit(10).get();40 const messages = [41 { role: 'system', content: SYSTEM_PROMPT },42 ...history.docs.reverse().map(d => ({43 role: d.data().role,44 content: d.data().content,45 })),46 ];4748 const completion = await openai.chat.completions.create({49 model: 'gpt-4o-mini',50 messages,51 max_tokens: 300,52 });5354 const reply = completion.choices[0].message.content;5556 // Save bot response57 await messagesRef.add({58 role: 'assistant',59 content: reply,60 timestamp: admin.firestore.FieldValue.serverTimestamp(),61 });6263 // Update session timestamp64 await db.collection('chat_sessions').doc(sessionId).update({65 lastMessageAt: admin.firestore.FieldValue.serverTimestamp(),66 });6768 return { reply };69});Expected result: The Cloud Function receives user messages, sends them to OpenAI with the knowledge base context and conversation history, and returns the bot's response.
Wire up the chat UI to the Cloud Function with typing indicator
Wire up the chat UI to the Cloud Function with typing indicator
On the Send button tap, create an Action Flow: (1) Read the TextField value and clear it immediately for better UX. (2) Set a Page State variable isTyping to true — this shows the three-dot typing indicator in the ListView. (3) Call the chatWithBot Cloud Function via an API Call action, passing sessionId and the message text. (4) On success, set isTyping to false. The real-time listener on the messages subcollection (Single Time Query OFF) will automatically display both the user message and bot response as they are written to Firestore. If the API call fails, show a SnackBar error and set isTyping to false. Also check: if the bot's response contains 'connect you with a support agent', automatically trigger the escalation flow.
Expected result: Sending a message shows the typing indicator, calls the Cloud Function, and displays both the user message and bot response in real time.
Implement live agent handoff when the bot cannot resolve the issue
Implement live agent handoff when the bot cannot resolve the issue
Track a Page State variable failedAttempts (Integer, starts at 0). When the bot's response contains phrases like 'I cannot help with that' or 'connect you with an agent', increment failedAttempts. When failedAttempts reaches 3 (or the user taps an Escalate button), update the chat_sessions document: set status to 'escalated' and escalatedAt to now. Display a system message: 'You have been connected to a support agent. Please wait for a response.' On the admin side, create a SupportQueue page listing sessions where status == 'escalated', ordered by escalatedAt ascending. Agents can claim a session (set agentId), view the full conversation history including bot messages, and reply directly. Agent messages are saved with role 'assistant' but a separate agentId field to distinguish from bot messages.
Expected result: After three failed bot attempts or manual escalation, the conversation transfers to a live agent queue. Agents see the full history and can continue the conversation.
Complete working example
1// Cloud Function: AI Customer Support Chatbot2const functions = require('firebase-functions');3const admin = require('firebase-admin');4const OpenAI = require('openai');5admin.initializeApp();67const openai = new OpenAI({8 apiKey: functions.config().openai.key,9});1011const SYSTEM_PROMPT = `You are a helpful customer support12assistant for [YourApp]. Answer questions using ONLY the13knowledge base below. If the answer is not in the knowledge14base, respond with: "I'm not sure about that. Let me15connect you with a support agent who can help."1617Knowledge Base:18- Pricing: Free (basic features), Pro $25/mo (all features)19- Returns: 30-day return policy, contact support@app.com20- Shipping: Standard 5-7 days ($5), Express 2-3 days ($15)21- Account: Reset password in Settings > Security > Change Password22- Billing: Update card in Settings > Billing > Payment Method23- Cancel: Settings > Subscription > Cancel (effective end of period)2425Tone: Friendly, concise, helpful. Use bullet points for lists.`;2627const SLIDING_WINDOW = 10; // Last N messages for context2829exports.chatWithBot = functions.https.onCall(async (data, ctx) => {30 if (!ctx.auth) throw new functions.https.HttpsError(31 'unauthenticated', 'Login required');3233 const { sessionId, message } = data;34 const db = admin.firestore();35 const sessionRef = db.collection('chat_sessions').doc(sessionId);36 const msgsRef = sessionRef.collection('messages');3738 // Check session is not escalated39 const session = await sessionRef.get();40 if (session.data()?.status === 'escalated') {41 return { reply: 'A support agent is handling your case.' };42 }4344 // Save user message45 const now = admin.firestore.FieldValue.serverTimestamp();46 await msgsRef.add({ role: 'user', content: message, timestamp: now });4748 // Load conversation window49 const snap = await msgsRef.orderBy('timestamp', 'desc')50 .limit(SLIDING_WINDOW).get();51 const apiMessages = [52 { role: 'system', content: SYSTEM_PROMPT },53 ...snap.docs.reverse().map(d => ({54 role: d.data().role, content: d.data().content,55 })),56 ];5758 // Call OpenAI59 const completion = await openai.chat.completions.create({60 model: 'gpt-4o-mini',61 messages: apiMessages,62 max_tokens: 300,63 temperature: 0.3, // Lower = more consistent support answers64 });65 const reply = completion.choices[0].message.content;6667 // Save bot response68 await msgsRef.add({ role: 'assistant', content: reply, timestamp: now });69 await sessionRef.update({ lastMessageAt: now });7071 // Auto-escalate if bot indicates it cannot help72 if (reply.toLowerCase().includes('connect you with')) {73 await sessionRef.update({ status: 'escalated', escalatedAt: now });74 }7576 return { reply };77});Common mistakes when implementing a Chatbot for Customer Support in FlutterFlow
Why it's a problem: Sending the entire conversation history to OpenAI on every message
How to avoid: Implement a sliding window that sends only the last 10 messages plus the system prompt. Optionally, summarize earlier messages into a condensed context note.
Why it's a problem: Storing the OpenAI API key in FlutterFlow's API Call configuration
How to avoid: Store the API key in Firebase Functions config (firebase functions:config:set openai.key=YOUR_KEY). The Cloud Function accesses it server-side, and the key never reaches the client.
Why it's a problem: Not implementing any handoff mechanism to live agents
How to avoid: Track failed attempts and auto-escalate after 3 unresolved attempts. Also provide a manual Escalate to Agent button so users can request human help at any time.
Best practices
- Use a detailed system prompt with your actual FAQ, policies, and product information for accurate responses
- Implement a sliding window of the last 10 messages to control API costs while maintaining context
- Set temperature to 0.3 or lower for support chatbots to get consistent, factual answers
- Show a typing indicator while waiting for the API response to set user expectations
- Clear the input TextField immediately on send for a snappier user experience
- Auto-escalate to a live agent when the bot indicates it cannot help with the question
- Store all messages in Firestore so agents can see the full conversation history when escalation occurs
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I'm building a customer support chatbot in FlutterFlow. I need a Cloud Function that calls OpenAI's Chat Completions API with my support knowledge base as the system prompt, a sliding window of the last 10 messages for context, a chat UI with user/bot message bubbles, and automatic escalation to a live agent after 3 failed attempts. Show me the Cloud Function code and FlutterFlow page layout.
Create a chatbot page with a reversed ListView showing message bubbles (user on right in blue, bot on left in grey), a text input with send button pinned at the bottom, and a typing indicator that shows while waiting for a response.
Frequently asked questions
Which OpenAI model should I use for a support chatbot?
Use gpt-4o-mini for most support chatbots. It is fast, cost-effective, and handles FAQ-style queries well. Use gpt-4o for complex troubleshooting that requires deeper reasoning.
How do I update the chatbot's knowledge base without redeploying?
Store the knowledge base content in a Firestore document. The Cloud Function reads it on each request to construct the system prompt. Non-technical team members can edit the knowledge base document without touching code.
Can I use Dialogflow instead of OpenAI?
Yes. Create a Dialogflow CX agent with intents for your support topics. Call the Dialogflow API from a Cloud Function instead of OpenAI. Dialogflow offers more structured conversation design but less flexibility for open-ended questions.
How do I handle multiple languages in the chatbot?
OpenAI models support many languages natively. Add an instruction in the system prompt: 'Respond in the same language the user writes in.' For structured knowledge bases, maintain translations in Firestore and include the appropriate language version in the prompt.
What are the costs of running an OpenAI-powered chatbot?
With gpt-4o-mini at approximately $0.15 per million input tokens and $0.60 per million output tokens, a typical support conversation of 10 messages costs roughly $0.001-0.005. At 1,000 conversations per month, expect about $1-5 in API costs.
Can RapidDev help build an enterprise support chatbot?
Yes. RapidDev can implement multi-channel support (in-app, email, SMS), knowledge base management with auto-training, conversation analytics, CSAT surveys, agent dashboards, and integration with help desk tools like Zendesk or Freshdesk.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation