widget_chat 0.0.19
widget_chat: ^0.0.19 copied to clipboard
Drop-in AI chatbot widget for Flutter, FlutterFlow & web — rich content, tools, multimodal, multi-language, dashboard-configured.
Widget Chat - AI Chatbot Widget #
A beautiful, customizable AI chatbot widget you can drop into any Flutter, FlutterFlow, React, or web app — rich content, tools, multimodal input, and multi-language, all configured from a no-code dashboard at widget-chat.com.
[Widget-Chat AI chat widget open on a website]
💬 Try the live widget at widget-chat.com (bottom-right) — it runs this exact package.
Features #
- 🎨 Beautiful UI: Modern, customizable design with smooth animations
- 🚀 Easy Integration: Single widget integration with minimal setup
- 🔒 Secure: Project-based authentication with secure keys
- 📱 Responsive: Adaptive design for mobile and web platforms
- ⚡ Real-time: Live chat with typing indicators
- 🎭 Customizable: Themes, colors, FAB styles, and behavior
- 🌐 Multi-platform: Works on iOS, Android, and Web
Installation #
Add to your pubspec.yaml:
dependencies:
widget_chat: ^0.0.10
Quick Start #
1. Import the package #
import 'package:widget_chat/widget_chat.dart';
2. Add the ChatWidget to your app #
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
// Your app content here
YourMainContent(),
// Add the chatbot
Positioned(
bottom: 20,
right: 20,
child: ChatWidget(
configuration: BotConfiguration(
projectSecretKey: 'your-project-secret-key',
userID: 'unique-user-id',
name: 'Support Bot',
welcomeMessage: 'Hello! How can I help you today?',
),
),
),
],
),
);
}
}
Configuration Options #
Basic Configuration #
BotConfiguration(
// Required
projectSecretKey: 'your-secret-key', // Get from your dashboard
userID: 'user-123', // Unique identifier for the user
// Optional
name: 'Assistant', // Bot display name
welcomeMessage: 'How can I help?', // Initial greeting
fontFamily: 'Roboto', // Chat font (default: Roboto)
color: '#3B82F6', // Primary color in hex
systemInstructions: 'Be helpful', // Bot behavior instructions
isPreviewMode: false, // Preview mode flag
)
FAB Customization #
BotConfiguration(
projectSecretKey: 'your-key',
userID: 'user-123',
fabConfiguration: FabConfiguration(
icon: 'chat_bubble', // Icon name
iconSize: 24.0, // Icon size
iconColor: '#FFFFFF', // Icon color in hex
backgroundColor: '#3B82F6', // Background color in hex
buttonSize: 56.0, // FAB size
borderRadius: 28.0, // Corner radius
useAvatarAsIcon: false, // Use avatar image as icon
),
)
Advanced Usage #
Responsive Design #
// Mobile (default) - full-screen chat experience
ChatWidget(
configuration: BotConfiguration(
projectSecretKey: 'your-key',
userID: 'user-123',
),
)
// Web/Desktop - fixed 400x700 chat window
ChatWidget(
configuration: BotConfiguration(
projectSecretKey: 'your-key',
userID: 'user-123',
),
mobile: false,
)
Custom FAB Widget #
ChatWidget(
configuration: BotConfiguration(
projectSecretKey: 'your-key',
userID: 'user-123',
),
fabWidget: CustomFABWidget(), // Your custom FAB
)
Chat State Callbacks #
ChatWidget(
configuration: BotConfiguration(
projectSecretKey: 'your-key',
userID: 'user-123',
),
onOpen: ({required bool isOpen}) {
print('Chat is ${isOpen ? "open" : "closed"}');
// Track analytics, update UI, etc.
},
)
Host App Integration #
The bot can drive your app — and your app can feed the bot — through four channels. All of them are optional; wire only what your product needs.
Rich-content action callbacks #
Backend tools and the model can emit buttons/cards whose taps land in YOUR code. Declare the callback ids your app handles in the dashboard project's callback registry (so the model can't invent ids you don't dispatch), then:
ChatWidget(
configuration: BotConfiguration(projectSecretKey: '...', userID: 'user-123'),
onRichContentCallback: (callbackId, payload) {
switch (callbackId) {
case 'open_item': navigateToItem(payload?['item']);
case 'open_paywall': showPaywall();
case 'open_login': showSignIn();
}
},
)
Tip — for navigation, prefer ONE generic id over per-feature ids: declare a
single open_screen callback whose payload['screen'] selects the
destination, and keep a {screenKey: route} map host-side. New destinations
then need no new callback ids — just a new key in the map and in the
registry description (which is also what tells the model the allowed keys):
case 'open_screen':
final route = screenRoutes[payload?['screen']]; // {'studio': StudioPage.route, ...}
if (route != null) Navigator.of(context).push(route());
Authenticated tool calls (authToken) #
Pass the END USER's JWT and the backend forwards it as a Bearer header to every tool call, so your API attributes actions to the right account:
BotConfiguration(
userID: user.id.toString(),
authToken: session.jwt, // re-read on EVERY send — refresh it proactively
)
authToken is re-read per message: rotate it mid-session with
updateConfiguration/a rebuild and the next tool call uses the fresh token.
Refresh BEFORE expiry (e.g. a 5-minute periodic check) — an expired token
makes every gated tool 401 and degrades the conversation.
Guest / anonymous sessions #
userID is any non-empty string — no account required. The recommended
pattern for apps with optional sign-in:
- Guests get a device-persistent id (
anon-<random>, stored in prefs) and NOauthToken. - Tell the bot who it's talking to via
userContext({'authenticated': false}), and gate account-bound tools in your system prompt AND in each tool's description ("SIGNED-IN USERS ONLY … emit the open_login button instead"). A required boolean parameter on gated tools (e.g.user_is_signed_in, "copy user_context.authenticated exactly") makes small models respect the gate far more reliably than prose alone. - On login, remount the chat keyed to the real user id — history scopes per
userID, so the guest thread stays behind and the account thread loads. - Disable attachments for guests (
enableFileAttach: false) when your upload endpoint needs auth.
User context (userContext) #
A free-form map injected into the system prompt on every send — entitlement flags, profile ids, supported callback vocabulary. Keep it small (tokenised each turn, 8 KB cap):
userContext: {
'authenticated': true,
'pro': user.isPro,
'supported_callbacks': ['open_item', 'open_paywall'],
}
Host slots #
Backend tools with execution_target: host_render reserve a spot in the
bubble that YOUR widget fills — the tool's arguments arrive as the payload:
hostSlotBuilder: (slotId, payload) =>
slotId == 'item_preview' ? ItemPreview(payload) : null,
Slot builders must be pure functions of the payload — history reloads re-render them from stored JSON.
Image uploads #
Wire imageUploader to your own storage and the chat sends compact URLs
instead of inlining base64 into the conversation:
imageUploader: (bytes, mimeType) async => myCdn.upload(bytes, mimeType),
Attached photos are forwarded by the backend to image-bearing tools (analysis, extraction, try-on style flows) — the model never handles raw bytes.
Theming that stays on brand #
Since 0.0.18 the chat pins its accent to your configured brand color in
BOTH light and dark mode (filled buttons, send icon, focus rings render the
exact color instead of a Material tonal derivative). Per-mode surfaces and
bubble colors come from the dashboard (chat_appearance /
chat_appearance_dark), with defaultThemeMode and an optional in-chat
theme switcher (showThemeToggle). Prefer configuring colors on the
dashboard over hard-coding them host-side — config survives app releases.
Platform-Specific Setup #
Mobile (Default) #
The mobile parameter defaults to true, so the chat opens in full-screen mode out of the box - ideal for iOS and Android apps.
Web / Desktop #
For web or desktop applications, set mobile: false to use a fixed-size (400x700) chat window:
ChatWidget(
configuration: config,
mobile: false,
)
The embedded iframe version (web_embed) already handles this automatically via URL parameters.
Available Icons #
The FAB supports these icon options:
chat_bubble(default)chatmessagesupport_agenthelpquestion_answerforumcontact_supportheadset_mic
Security Best Practices #
- Never expose your project secret key in client-side code
- Use unique user IDs to maintain conversation history
- Configure allowed origins for web deployments
- Keep your SDK updated for security patches
Example App #
Check out the complete example in the /example folder:
import 'package:flutter/material.dart';
import 'package:widget_chat/widget_chat.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Widget Chat Example',
home: Scaffold(
body: Stack(
children: [
Center(
child: Text('Your App Content'),
),
Positioned(
bottom: 20,
right: 20,
child: ChatWidget(
configuration: BotConfiguration(
projectSecretKey: 'your-project-secret-key',
userID: 'demo-user',
name: 'AI Assistant',
welcomeMessage: 'Hi! How can I help you today?',
color: '#6366F1',
fabConfiguration: FabConfiguration(
icon: 'support_agent',
backgroundColor: '#6366F1',
),
),
),
),
],
),
),
);
}
}
Troubleshooting #
Chat doesn't open #
- Verify your project secret key is correct
- Check console for any error messages
- Ensure the widget is properly positioned in your widget tree
Styling issues #
- Make sure hex colors include the # symbol
- Use supported Google Fonts for fontFamily
- Check that size values are reasonable (e.g., buttonSize: 56.0)
Support #
- Documentation: https://docs.widget-chat.com
- Email: support@widget-chat.com
- GitHub Issues: Report bugs here
License #
This project is licensed under the Proprietary License - see the LICENSE file for details.
