Initialization & Authentication
| Practice | Description |
|---|---|
| Initialize once at startup | Call CometChat.init() in your main() or root widget’s initState(). It only needs to be called once per session. |
| Use environment variables | Store App ID, Region, and Auth Key in a config file or environment variables rather than hardcoding them. |
| Check for existing sessions | Before calling login(), use CometChat.getLoggedInUser() to check if a session already exists. |
| Use Auth Tokens in production | Auth Keys are for development only. Generate Auth Tokens server-side using the REST API. |
| Handle token expiry | Implement a mechanism to detect login failures due to expired tokens. Use the Login Listener to detect session changes. |
| Logout on sign-out | Always call CometChat.logout() when your user signs out to clear the SDK session and stop real-time events. |
Listeners
| Practice | Description |
|---|---|
| Use unique listener IDs | Use descriptive IDs like "MESSAGE_LISTENER_CHAT_SCREEN" to avoid accidental overwrites. |
| Register early, remove on cleanup | Register listeners after login(). Remove them in your widget’s dispose() method to prevent memory leaks. |
| Keep callbacks lightweight | Avoid heavy processing inside listener callbacks. Use setState() or dispatch events to your state management layer. |
| Use specific listeners | Only register the listener types you need. Don’t register a GroupListener if your page only handles messages. |
Pagination & Caching
| Practice | Description |
|---|---|
| Use reasonable limits | Set setLimit() to 30–50 for users, messages, and group members. |
| Reuse request objects | Call fetchNext()/fetchPrevious() on the same request instance. Creating a new object resets the cursor. |
| Cache frequently accessed data | Store user and group objects locally to reduce API calls. |
Rate Limits
| Practice | Description |
|---|---|
| Batch operations | Space out bulk operations using a queue or throttle mechanism. |
| Distinguish operation types | Core operations (login, create/delete user) share a 10,000/min limit. Standard operations have 20,000/min. Avoid frequent login/logout cycles. |
Messaging
| Practice | Description |
|---|---|
| Use appropriate message types | Choose text, media, or custom messages based on your content. |
| Add metadata for context | Use metadata to attach location, device info, or other contextual data to messages. |
| Handle errors gracefully | Always implement onError callbacks to handle network issues or invalid parameters. |
| Validate file types | Before sending media messages, verify the file type matches the message type. |
| Hide deleted/blocked content | Use hideDeletedMessages(true) and hideMessagesFromBlockedUsers(true) on your MessagesRequestBuilder for cleaner lists. |
Threaded Messages
| Practice | Description |
|---|---|
| Track active thread ID | Store the current thread’s parentMessageId to filter incoming messages. |
| Use hideReplies(true) | Exclude thread replies from main conversation to avoid clutter. |
| Show reply count | Display the number of replies on parent messages to indicate thread activity. |
Reactions & Mentions
| Practice | Description |
|---|---|
| Update UI optimistically | Show reactions immediately, then sync with server response. |
| Use correct mention format | Always use <@uid:UID> format for mentions in message text. |
| Highlight mentions in UI | Parse message text and style mentions differently using Flutter’s RichText or Text.rich. |
Typing Indicators
| Practice | Description |
|---|---|
| Debounce typing events | Don’t call startTyping() on every keystroke — debounce to ~300ms intervals. |
| Auto-stop typing | Call endTyping() after 3–5 seconds of inactivity or when the user sends a message. |
Delivery & Read Receipts
| Practice | Description |
|---|---|
| Mark as delivered on fetch | Call markAsDelivered() when messages are fetched and displayed. |
| Mark as read on view | Call markAsRead() when the user actually views/scrolls to a message. |
| Batch receipts | Mark the last message in a batch — all previous messages are automatically marked. |
Groups
| Practice | Description |
|---|---|
| Use meaningful GUIDs | Choose descriptive, unique GUIDs (e.g., "project-alpha-team"). |
| Set group type carefully | Group type cannot be changed after creation. Choose between public, password, and private. |
| Add members at creation | Use createGroupWithMembers() to add initial members in a single API call. |
| Check hasJoined before joining | Avoid unnecessary API calls by checking the group’s hasJoined property first. |
| Transfer ownership before leaving | Owners must transfer ownership to another member before they can leave. |
| Use joinedOnly(true) | Filter to joined groups when building sidebars or group lists. |
Group Members
| Practice | Description |
|---|---|
| Batch member additions | Add multiple members in a single addMembersToGroup() call. |
| Set appropriate scopes | Assign participant by default. Only use admin or moderator when needed. |
| Handle partial failures | Check each entry in the response map for success or error messages. |
| Kick vs. Ban | Use kick when the user can rejoin. Use ban for permanent removal until unbanned. |
Calling
| Practice | Description |
|---|---|
| Initialize Calls SDK after Chat SDK | Always initialize Chat SDK (CometChat.init()) before Calls SDK (CometChatCalls.init()). |
| Store session ID immediately | Save the session ID from initiateCall() response — you’ll need it for accept, reject, cancel. |
| Handle all call states | Implement handlers for all listener events (accepted, rejected, cancelled, busy, ended). |
| Generate tokens just-in-time | Generate call tokens immediately before starting a session rather than caching them. |
| Clean up on session end | Always call CometChatCalls.endSession() in both onCallEnded and onCallEndButtonPressed callbacks. |
| Inform users about recording | Always notify participants when recording starts — this is often a legal requirement. |
| Limit presenters to 5 | Additional users should join as viewers. |
Connection & WebSocket
| Practice | Description |
|---|---|
| Register connection listener early | Add the listener right after CometChat.init() succeeds. |
| Show connection status in UI | Display a banner when disconnected so users know messages may be delayed. |
| Queue actions during disconnection | Queue user actions and retry once onConnected fires. |
| Don’t poll getConnectionStatus() | Use the listener-based approach instead. |
| Reconnect on app foreground | If you disconnect in background, call CometChat.connect() when returning to foreground. |
Flutter-Specific Practices
| Practice | Description |
|---|---|
| iOS Podfile configuration | Run pod install in the ios/ directory after adding the SDK dependency. Set the minimum iOS deployment target as required. |
| Android minimum API level | Ensure minSdkVersion in android/app/build.gradle meets the SDK requirement. |
Use dispose() for cleanup | Always remove listeners and cancel subscriptions in your widget’s dispose() method. |
Use debugPrint for logging | Prefer debugPrint() over print() for SDK-related logging — it handles long strings and is stripped in release builds. |
| Handle platform exceptions | CometChat methods may throw PlatformException from native channels. Wrap calls in try/catch blocks. |
| State management integration | Dispatch SDK events to your state management layer (Provider, Bloc, Riverpod) rather than calling setState() directly in listener callbacks. |
Upgrading from V3
| Practice | Description |
|---|---|
| Follow the setup guide first | Complete the v4 setup instructions before changing dependencies. |
| Update pubspec.yaml | Replace the v3 cometchat_pro dependency with the v4 cometchat_sdk package. |
| Test incrementally | Test each feature area (messaging, calling, groups) individually after updating. |
| Remove old packages | Remove v3 packages from pubspec.yaml and run flutter pub get to avoid conflicts. |
Next Steps
Troubleshooting
Common issues and solutions
Setup SDK
Installation and initialization guide