Initialization & Authentication
| Practice | Description |
|---|---|
| Initialize once at app startup | Call CometChat.init() in your Application class onCreate(). It only needs to be called once per session. |
Store credentials in local.properties | Keep App ID, Region, and Auth Key out of source control. Read them via BuildConfig fields set in build.gradle. |
| 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. |
Activity & Fragment Lifecycle
| Practice | Description |
|---|---|
Register listeners in onResume() | Re-register message and call listeners when the Activity or Fragment becomes visible. |
Remove listeners in onPause() | Remove listeners in onPause() to avoid processing events while the screen is not visible. |
Clean up in onDestroy() | Remove all remaining listeners and cancel pending requests in onDestroy() to prevent memory leaks. |
Use ViewModel for SDK state | Hold SDK data (messages, users, groups) in a ViewModel so it survives configuration changes like screen rotation. |
Avoid SDK calls in onCreate() before init() | Ensure CometChat.init() has completed (in your Application class) before making any SDK calls in an Activity. |
Listeners
| Practice | Description |
|---|---|
| Use unique listener IDs | Use descriptive IDs like "MESSAGE_LISTENER_CHAT_SCREEN" to avoid accidental overwrites. |
| Register after login, remove on cleanup | Register listeners after login() succeeds. Remove them in onPause() or onDestroy() to prevent memory leaks. |
| Keep callbacks lightweight | Avoid heavy processing inside listener callbacks. Post updates to your ViewModel or LiveData. |
| Use specific listeners | Only register the listener types you need. Don’t register a GroupListener if your screen 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 in your ViewModel or a local Room database to reduce API calls. |
Rate Limits
| Practice | Description |
|---|---|
| Batch operations | Space out bulk operations using a queue or throttle mechanism. |
| Monitor rate limit headers | Check X-Rate-Limit-Remaining in REST API responses to slow down before hitting limits. |
| 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 setMetadata() to attach location, device info, or other contextual data. |
| 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) 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 the 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 the 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 SpannableString. |
Typing Indicators
| Practice | Description |
|---|---|
| Debounce typing events | Don’t call startTyping() on every keystroke — debounce to ~300ms intervals using a Handler or debounce operator. |
| 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 or 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 for "success" or an error message. |
| Use scope constants | Use CometChatConstants.SCOPE_ADMIN instead of raw strings. |
| 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, and 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. |
| Request permissions before calling | Check and request CAMERA and RECORD_AUDIO permissions at runtime before initiating a call. |
| 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. |
Permissions
| Practice | Description |
|---|---|
| Request permissions at the right time | Request CAMERA, RECORD_AUDIO, and READ_EXTERNAL_STORAGE permissions contextually, not at app launch. |
| Handle permission denial gracefully | Show a rationale dialog if the user denies a permission, and disable the relevant feature rather than crashing. |
Use ActivityResultContracts | Use the modern registerForActivityResult API instead of the deprecated onRequestPermissionsResult. |
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 | Call CometChat.connect() in onResume() if you disconnect in the background. |
AI Features
| Practice | Description |
|---|---|
| Register both listeners for AI Agents | Use AIAssistantListener for streaming events and MessageListener for persisted messages. |
| Handle streaming progressively | Render the assistant’s reply token-by-token using Text Message Content events. |
| Show pending state for moderation | Display a visual indicator when getModerationStatus() returns PENDING. |
| Handle disapproved messages gracefully | Show a placeholder or notification so the sender understands what happened. |
| Track pending messages | Maintain a local map of pending message IDs to update UI when moderation results arrive. |
Upgrading from V3
| Practice | Description |
|---|---|
| Follow the setup guide first | Complete the v4 setup instructions before changing dependencies. |
| Update Gradle dependency | Replace the v3 artifact with com.cometchat:chat-sdk-android:4.x.x in your build.gradle. |
| Test incrementally | Test each feature area (messaging, calling, groups) individually after updating. |
| Remove old packages | Remove the v3 dependency from build.gradle and sync to avoid conflicts. |
Next Steps
Troubleshooting
Common issues and solutions
Setup SDK
Installation and initialization guide