# 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/ios/chat/), the message exposes the following fields. ```swift chatMessage.messageID // String — unique ID; needed for delete operations chatMessage.timeStamp // Int — milliseconds since epoch chatMessage.isChatToAll // Bool — true for public messages, false for private chatMessage.isSelfSend // Bool — true if the local user sent this message chatMessage.receiverUser // ZoomVideoSDKUser? — the recipient for a private message; nil when isChatToAll is true ``` ```objectivec chatMessage.messageID; // NSString — unique ID; needed for delete operations chatMessage.timeStamp; // long long — milliseconds since epoch chatMessage.isChatToAll; // BOOL — true for public messages, false for private chatMessage.isSelfSend; // BOOL — true if the local user sent this message chatMessage.receiverUser; // ZoomVideoSDKUser — the recipient for a private message; nil 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 SDK whether it's deletable in the current context. ```swift guard let chatHelper = ZoomVideoSDK.shareInstance()?.getChatHelper() else { return } let messageID = chatMessage.messageID if chatHelper.canChatMessageBeDeleted(messageID) { let result = chatHelper.deleteChatMessage(messageID) if result != .Errors_Success { // Surface the error to the user. } } ``` ```objectivec ZoomVideoSDKChatHelper *chatHelper = [[ZoomVideoSDK shareInstance] getChatHelper]; NSString *messageID = chatMessage.messageID; if ([chatHelper canChatMessageBeDeleted:messageID]) { ZoomVideoSDKError result = [chatHelper deleteChatMessage:messageID]; if (result != Errors_Success) { // Surface the error to the user. } } ``` ### Listen for deletions When any message is deleted, the SDK fires `onChatMsgDeleteNotification` 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. ```swift func onChatMsgDeleteNotification(_ helper: ZoomVideoSDKChatHelper?, messageID msgID: String?, deleteBy type: ZoomVideoSDKChatMsgDeleteBy) { // Remove the message with id msgID from your UI. // Optionally show "Message removed by {host|sender|compliance}" using type. } ``` ```objectivec - (void)onChatMsgDeleteNotification:(ZoomVideoSDKChatHelper *)helper messageID:(NSString *)msgID deleteBy:(ZoomVideoSDKChatMsgDeleteBy)type { // Remove the message with id msgID from your UI. // Optionally show "Message removed by {host|sender|compliance}" using type. } ``` ### Delete-initiator values `ZoomVideoSDKChatMsgDeleteBy` tells you who deleted the message. | Value | Meaning | | ---------------------------------- | --------------------------------------------------------------------------------------- | | `ZoomVideoSDKChatMsgDeleteBy_NONE` | Initialization value, not used in a real callback. | | `ZoomVideoSDKChatMsgDeleteBy_SELF` | The message author deleted their own message. | | `ZoomVideoSDKChatMsgDeleteBy_HOST` | The session host deleted the message. | | `ZoomVideoSDKChatMsgDeleteBy_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. ```swift guard let chatHelper = ZoomVideoSDK.shareInstance()?.getChatHelper() else { return } // Read the current privilege (any user). let privilege = chatHelper.getChatPrivilege() // Change the privilege (host or manager only). let result = chatHelper.changeChatPrivilege(.Everyone_Publicly) if result != .Errors_Success { // Privilege change was rejected — most commonly because the local // user isn't the host or manager. } ``` ```objectivec ZoomVideoSDKChatHelper *chatHelper = [[ZoomVideoSDK shareInstance] getChatHelper]; // Read the current privilege (any user). ZoomVideoSDKChatPrivilegeType privilege = [chatHelper getChatPrivilege]; // Change the privilege (host or manager only). ZoomVideoSDKError result = [chatHelper changeChatPrivilege:ZoomVideoSDKChatPrivilege_Everyone_Publicly]; if (result != 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_Everyone_Publicly_And_Privately` | Participants can send public and private chat. | | `ZoomVideoSDKChatPrivilege_Everyone_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. ```swift func onChatPrivilegeChanged(_ helper: ZoomVideoSDKChatHelper?, privilege currentPrivilege: ZoomVideoSDKChatPrivilegeType) { switch currentPrivilege { case .No_One: hideChatComposer() case .Everyone_Publicly: showComposerWithoutPrivateOption() case .Everyone_Publicly_And_Privately: showFullComposer() default: break } } ``` ```objectivec - (void)onChatPrivilegeChanged:(ZoomVideoSDKChatHelper *)helper privilege:(ZoomVideoSDKChatPrivilegeType)currentPrivilege { switch (currentPrivilege) { case ZoomVideoSDKChatPrivilege_No_One: [self hideChatComposer]; break; case ZoomVideoSDKChatPrivilege_Everyone_Publicly: [self showComposerWithoutPrivateOption]; break; case ZoomVideoSDKChatPrivilege_Everyone_Publicly_And_Privately: [self 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.