Skip to main content
The crow_flutter package adds Crow to any Flutter app. Use CrowWidget for a floating chat button that overlays your existing app, drop in CrowChatView for a full-screen chat experience, or use CrowChatNotifier directly to build a fully custom interface.

Installation

flutter pub add crow_flutter

Quick Start

Add CrowWidget inside a Stack to get a floating chat button that slides up a chat sheet — zero extra UI work:
import 'package:crow_flutter/crow_flutter.dart';
import 'package:flutter/material.dart';

void main() => runApp(
  const CrowScope(
    productId: 'YOUR_PRODUCT_ID',
    child: MyApp(),
  ),
);

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // builder wraps every route — CrowWidget appears on all pages
      builder: (context, child) => Stack(
        children: [child!, const CrowWidget()],
      ),
      home: const HomeScreen(),
    );
  }
}
Placing CrowWidget in MaterialApp.builder means it automatically appears on every page and route in your app — no need to add it to each screen individually. Tapping the button slides up a chat sheet at 85% screen height.

Full-screen chat

Wrap your app with CrowScope and drop in CrowChatView as the full body:
import 'package:crow_flutter/crow_flutter.dart';
import 'package:flutter/material.dart';

void main() => runApp(
  const CrowScope(
    productId: 'YOUR_PRODUCT_ID',
    child: MyApp(),
  ),
);

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(body: CrowChatView()),
    );
  }
}
CrowChatView includes message bubbles, streaming, conversation history, suggested actions, and a “Powered by Crow” footer — no additional setup required.

CrowScope Props

CrowScope is an InheritedWidget that provides the client and state down the widget tree.
PropRequiredDescription
productIdYesYour product ID from the dashboard
apiUrlNoAPI URL (defaults to https://api.usecrow.org)
modelNoOverride the default model
identityTokenNoJWT token for authenticated users
storageNoCustom storage adapter. Defaults to SharedPreferences

CrowWidget Props

PropRequiredDescription
themeNoCrowTheme instance to customize the chat sheet appearance

CrowChatView Props

PropRequiredDescription
themeNoCrowTheme instance to customize appearance

Theming

Customize colors and styles via CrowTheme:
CrowChatView(
  theme: CrowTheme(
    backgroundColor: Colors.white,
    userBubbleColor: Colors.white,
    userBubbleTextColor: const Color(0xFF111827),
    assistantBubbleColor: Colors.black,
    assistantBubbleTextColor: Colors.white,
    inputBorderColor: const Color(0xFFE5E7EB),
    sendButtonColor: Colors.black,
    bubbleBorderRadius: 18.0,
    poweredByColor: const Color(0xFF9CA3AF),
  ),
)

Theme Properties

PropertyDescription
backgroundColorChat background color
userBubbleColorUser message bubble background
userBubbleTextColorUser message text color
assistantBubbleColorAssistant bubble background
assistantBubbleTextColorAssistant message text color
sendButtonColorSend button color
bubbleBorderRadiusCorner radius for message bubbles
inputBorderColorInput bar border color
inputBorderLoadingColorInput border color while streaming
poweredByColor”Powered by Crow” text color
headerBorderColorBottom border of the header
messageTextStyleFull TextStyle override for message text
inputDecorationFull InputDecoration override for the text field

Custom UI (Headless)

Access CrowChatNotifier directly via CrowScope.chatOf(context) to build your own UI:
class MyChatScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final notifier = CrowScope.chatOf(context);

    return ListenableBuilder(
      listenable: notifier,
      builder: (context, _) {
        final state = notifier.state;

        return Column(
          children: [
            Expanded(
              child: ListView.builder(
                itemCount: state.messages.length,
                itemBuilder: (context, i) => Text(state.messages[i].content),
              ),
            ),
            if (state.isLoading) const CircularProgressIndicator(),
          ],
        );
      },
    );
  }
}

CrowChatState

PropertyTypeDescription
messagesList<Message>All messages in the current conversation
isLoadingboolAgent is currently streaming a response
suggestedActionsList<SuggestedAction>Quick reply suggestions from the agent
isIdentifiedboolA token has been set for this user
isVerifiedboolServer confirmed the user’s identity

CrowChatNotifier Methods

MethodDescription
sendMessage(String)Send a message and stream the response
stop()Cancel the current streaming response
clear()Clear messages and start a new conversation
identify(IdentifyOptions)Set a user identity token
resetUser()Log out the current user

Message Type

class Message {
  final String id;
  final MessageRole role;   // MessageRole.user or MessageRole.assistant
  final String content;
  final DateTime timestamp;
  final bool isStreaming;
  final List<Citation> citations;
}

User Identity

Identify users to enable conversation history and personalized responses:
final notifier = CrowScope.chatOf(context);

// From a login handler
final token = await fetchTokenFromYourBackend();
notifier.identify(IdentifyOptions(token: token));

// Or pass via CrowScope props (auto-updates when token changes)
CrowScope(
  productId: 'YOUR_PRODUCT_ID',
  identityToken: userToken,
  child: MyApp(),
)

// Logout
notifier.resetUser();
See Identity Verification for generating tokens on your backend.

Client-Side Tools

Register tools that run natively in your Flutter app:
final client = CrowScope.clientOf(context);

client.registerTool('navigateToScreen', (params) async {
  final screen = params['screen'] as String;
  Navigator.pushNamed(context, '/$screen');
  return ToolResult.success({'navigated_to': screen});
});

client.registerTool('addToCart', (params) async {
  final productId = params['product_id'] as String;
  await cartController.add(productId);
  return ToolResult.success({'added': productId});
});
Upload tool definitions on the Actions page so the agent knows when to call them.

Platform Support

PlatformSupport
iOS
Android
macOS
Web

iOS / macOS

No additional configuration needed. For macOS apps, add the outbound networking entitlement — required for all network calls, including production:
<!-- macos/Runner/DebugProfile.entitlements -->
<key>com.apple.security.network.client</key>
<true/>

Differences from Other SDKs

Web (@usecrow/ui)React NativeFlutter
LanguageTypeScriptTypeScriptDart
Drop-in UI<CrowWidget /><CrowWidget />CrowWidget
StateuseChat() hookuseChat() hookCrowChatNotifier
StoragelocalStorageAsyncStorage adapterSharedPreferences (built-in)
Provider<CrowProvider><CrowProvider>CrowScope