Getting Started

This guide walks you through adding a fully working chat screen to a Flutter app in minutes using the stream_chat_flutter package.

Add the dependency

flutter pub add stream_chat_flutter

Or add it to pubspec.yaml manually:

dependencies:
  stream_chat_flutter: ^10.0.0

Initialize the client

Create a StreamChatClient with your API key and connect the current user before entering the widget tree:

import 'package:stream_chat_flutter/stream_chat_flutter.dart';

final client = StreamChatClient('YOUR_API_KEY', logLevel: Level.OFF);

await client.connectUser(
  User(id: 'user-id', name: 'Jane Doe'),
  client.devToken('user-id').rawValue, // dev token only — use a real token in production
);

Wrap your app in StreamChat

StreamChat provides the client, theme, and config to all widgets below it:

MaterialApp(
  builder: (context, child) => StreamChat(
    client: client,
    child: child!,
  ),
  home: const ChannelListPage(),
)

Add a channel list screen

StreamChannelListView renders a scrollable, real-time channel list. Tapping a row navigates to the channel screen:

class ChannelListPage extends StatefulWidget {
  const ChannelListPage({super.key});

  @override
  State<ChannelListPage> createState() => _ChannelListPageState();
}

class _ChannelListPageState extends State<ChannelListPage> {
  late final _controller = StreamChannelListController(
    client: StreamChat.of(context).client,
    filter: Filter.in_('members', [StreamChat.of(context).currentUser!.id]),
    channelStateSort: const [SortOption<ChannelState>.desc('last_message_at')],
  );

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: const StreamChannelListHeader(),
      body: StreamChannelListView(
        controller: _controller,
        onChannelTap: (channel) => Navigator.push(
          context,
          MaterialPageRoute(
            builder: (_) => StreamChannel(
              channel: channel,
              child: const ChannelPage(),
            ),
          ),
        ),
      ),
    );
  }
}

Add a channel (chat) screen

A channel screen combines three widgets stacked in a Scaffold:

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: const StreamChannelHeader(),
      body: Column(
        children: [
          Expanded(
            child: StreamMessageListView(
              threadBuilder: (_, parentMessage) => StreamChannel(
                channel: StreamChannel.of(context).channel,
                child: ThreadPage(parent: parentMessage),
              ),
            ),
          ),
          const StreamMessageComposer(),
        ],
      ),
    );
  }
}

StreamChannel (the InheritedWidget wrapping ChannelPage in the navigation call above) makes the channel available to StreamChannelHeader, StreamMessageListView, and StreamMessageComposer without any additional wiring.

Platform requirements

Android

The package uses photo_manager for media access. Follow the Android 10+ wiki to configure permissions.

iOS

Add usage descriptions to Info.plist as required by flutter_file_picker, video_player, and image_picker.

Web

Add oncontextmenu="return false;" to the <body> tag in index.html to let the SDK override right-click behavior.

macOS

Add the file_selector entitlements for network and file access to both Release.entitlements and DebugProfile.entitlements.

Next steps