# Manage chat messages After a chat message arrives, you can read its metadata, delete it, and control who can chat through host privileges. ## Read message metadata Every `onChatNewMessageNotify` callback receives a `ZoomVideoSDKChatMessage`. In addition to the sender and content shown in [Core features](/docs/video-sdk/android/chat/), the message exposes the following fields. ```kotlin messageItem.messageId // String — unique ID; needed for delete operations messageItem.timeStamp // Long — milliseconds since epoch messageItem.isChatToAll // Boolean — true for public messages, false for private messageItem.isSelfSend // Boolean — true if the local user sent this message messageItem.receiverUser // ZoomVideoSDKUser? — the recipient for a private message; null when isChatToAll is true ``` ```java messageItem.getMessageId(); // String — unique ID; needed for delete operations messageItem.getTimeStamp(); // long — milliseconds since epoch messageItem.isChatToAll(); // boolean — true for public messages, false for private messageItem.isSelfSend(); // boolean — true if the local user sent this message messageItem.getReceiverUser(); // ZoomVideoSDKUser — the recipient for a private message; null when isChatToAll is true ``` ## Delete a chat message A user can delete a message they sent; a host can delete any message in the session; and a compliance system can delete a message under a data-loss-prevention policy. Before exposing a delete UI for a given message, ask the Video SDK for Android whether it's deletable in the current context. ```kotlin val chatHelper = ZoomVideoSDK.getInstance().chatHelper val messageId = messageItem.messageId if (chatHelper.canChatMessageBeDeleted(messageId)) { val result = chatHelper.deleteChatMessage(messageId) if (result != ZoomVideoSDKErrors.Errors_Success) { // Surface the error to the user. } } ``` ```java ZoomVideoSDKChatHelper chatHelper = ZoomVideoSDK.getInstance().getChatHelper(); String messageId = messageItem.getMessageId(); if (chatHelper.canChatMessageBeDeleted(messageId)) { int result = chatHelper.deleteChatMessage(messageId); if (result != ZoomVideoSDKErrors.Errors_Success) { // Surface the error to the user. } } ``` ### Listen for deletions When any message is deleted, the SDK fires `onChatDeleteMessageNotify` on every user's device. Remove the message from your UI from this callback so it stays in sync regardless of who initiated the delete. ```kotlin override fun onChatDeleteMessageNotify( chatHelper: ZoomVideoSDKChatHelper?, msgID: String?, deleteBy: ZoomVideoSDKChatMessageDeleteType? ) { // Remove the message with id msgID from your RecyclerView adapter. // Optionally show "Message removed by {host|sender|compliance}" using deleteBy. } ``` ```java @Override public void onChatDeleteMessageNotify( ZoomVideoSDKChatHelper chatHelper, String msgID, ZoomVideoSDKChatMessageDeleteType deleteBy ) { // Remove the message with id msgID from your RecyclerView adapter. // Optionally show "Message removed by {host|sender|compliance}" using deleteBy. } ``` ### Delete-initiator values `ZoomVideoSDKChatMessageDeleteType` tells you who deleted the message: | Value | Meaning | | ------------------------- | --------------------------------------------------------------------------------------- | | `SDK_CHAT_DELETE_BY_NONE` | Initialization value, not used in a real callback. | | `SDK_CHAT_DELETE_BY_SELF` | The message author deleted their own message. | | `SDK_CHAT_DELETE_BY_HOST` | The session host deleted the message. | | `SDK_CHAT_DELETE_BY_DLP` | A Data Loss Prevention (DLP) policy removed the message for violating compliance rules. | ## Host control: chat privileges The session host (or a session manager) can change what kind of chat participants are allowed using `changeChatPrivilege`. Privilege changes fire `onChatPrivilegeChanged` on every user's device. Use that callback to enable or disable your composer. ```kotlin val chatHelper = ZoomVideoSDK.getInstance().chatHelper // Read the current privilege (any user). val privilege = chatHelper.chatPrivilege // Change the privilege (host or manager only). val result = chatHelper.changeChatPrivilege( ZoomVideoSDKChatPrivilegeType.ZoomVideoSDKChatPrivilege_Publicly ) if (result != ZoomVideoSDKErrors.Errors_Success) { // Privilege change was rejected — most commonly because the local // user isn't the host or manager. } ``` ```java ZoomVideoSDKChatHelper chatHelper = ZoomVideoSDK.getInstance().getChatHelper(); // Read the current privilege (any user). ZoomVideoSDKChatPrivilegeType privilege = chatHelper.getChatPrivilege(); // Change the privilege (host or manager only). int result = chatHelper.changeChatPrivilege( ZoomVideoSDKChatPrivilegeType.ZoomVideoSDKChatPrivilege_Publicly ); if (result != ZoomVideoSDKErrors.Errors_Success) { // Privilege change was rejected — most commonly because the local // user isn't the host or manager. } ``` ### Privilege values `ZoomVideoSDKChatPrivilegeType` controls what kinds of chat participants can send. | Value | Effect | | -------------------------------------------------- | ----------------------------------------------------------------- | | `ZoomVideoSDKChatPrivilege_Unknown` | Uninitialized. Should not appear in a real session. | | `ZoomVideoSDKChatPrivilege_Publicly_And_Privately` | Participants can send public and private chat. | | `ZoomVideoSDKChatPrivilege_Publicly` | Participants can send public chat only. Private messaging is off. | | `ZoomVideoSDKChatPrivilege_No_One` | Chat is fully disabled for non-host participants. | ### React to privilege changes Handle `onChatPrivilegeChanged` and update your composer to match the new privilege. ```kotlin override fun onChatPrivilegeChanged( chatHelper: ZoomVideoSDKChatHelper?, currentPrivilege: ZoomVideoSDKChatPrivilegeType? ) { when (currentPrivilege) { ZoomVideoSDKChatPrivilegeType.ZoomVideoSDKChatPrivilege_No_One -> hideChatComposer() ZoomVideoSDKChatPrivilegeType.ZoomVideoSDKChatPrivilege_Publicly -> showComposerWithoutPrivateOption() ZoomVideoSDKChatPrivilegeType.ZoomVideoSDKChatPrivilege_Publicly_And_Privately -> showFullComposer() else -> {} } } ``` ```java @Override public void onChatPrivilegeChanged( ZoomVideoSDKChatHelper chatHelper, ZoomVideoSDKChatPrivilegeType currentPrivilege ) { switch (currentPrivilege) { case ZoomVideoSDKChatPrivilege_No_One: hideChatComposer(); break; case ZoomVideoSDKChatPrivilege_Publicly: showComposerWithoutPrivateOption(); break; case ZoomVideoSDKChatPrivilege_Publicly_And_Privately: showFullComposer(); break; default: break; } } ``` If you only need a boolean "is chat available right now" check rather than the specific privilege value, the `isChatDisabled` and `isPrivateChatDisabled` helpers on `ZoomVideoSDKChatHelper` are easier to read at the call site.