final client = StreamChatClient('your-api-key');
await client.connectUserWithProvider(
User(id: 'user-id'),
(String userId) async => await fetchToken(userId),
);Going Live Checklist
Before releasing your Stream Chat Flutter integration to production, work through this checklist to avoid common pitfalls and ensure a smooth launch.
Authentication
Use server-side token generation. Development tokens (generated client-side or hardcoded) are only suitable for local testing. Before going live, your backend must generate user tokens using your Stream API secret. Never ship your API secret in the app binary.
Use expiring tokens. Tokens with an expiry date limit the blast radius if a token is compromised. Implement a tokenProvider callback on StreamChatClient so the SDK can refresh tokens automatically:
Sensitive data
Never store your Stream API secret in the app. It can be extracted from the binary by attackers. Keep it on your server only.
Review local storage. If you have offline support enabled, message content is persisted to the device. Confirm this meets your privacy and compliance requirements.
Logout and user switching
Always await disconnect before switching users. The SDK uses persistent local storage. Switching users without waiting for disconnect to complete can throw User already getting connected, try calling disconnectUser:
await client.disconnectUser();
// now it is safe to connect a different user
await client.connectUser(newUser, newToken);Performance
Test under realistic load. For channels with many concurrent users (livestreams, large groups), run load tests before launch. Stream provides the benchat repository with scripts that simulate many users sending messages simultaneously.
Avoid rebuilding controllers in widget build methods. Creating a StreamChannelListController or other controller inside build causes it to be recreated on every rebuild. Define controllers in initState or State fields:
// Correct
class _MyPageState extends State<MyPage> {
late final _controller = StreamChannelListController(...);
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}Dispose controllers. Always call dispose() on StreamChannelListController, StreamMessageComposerController, and other controllers when the widget is removed from the tree to free resources and cancel subscriptions.
Push notifications
Test on a physical device. Push notifications do not work on iOS simulators. Verify that your APNs / FCM configuration works end-to-end on a real device before release.
Handle background messages. Ensure your background message handler processes Stream payloads and avoids performing UI operations, since no UI context is available in the background.
Logging
Reduce the log level in production. Use Level.WARNING or Level.SEVERE rather than Level.ALL to minimise performance overhead and avoid leaking sensitive information to log aggregators:
final client = StreamChatClient(
'your-api-key',
logLevel: kDebugMode ? Level.ALL : Level.WARNING,
);App store submissions
iOS Info.plist permissions. If your app uses the attachment picker, push notifications, or location sharing, ensure all required NSUsageDescription keys are present in Info.plist. Missing descriptions cause App Store rejection.
Android permissions. Review AndroidManifest.xml for all required permissions (storage, camera, microphone for voice recording). Remove any permissions your app does not actually use.
If you have questions about your integration or encounter issues, contact Stream support.