ChatActions feature provides methods for managing chat organization through archiving, pinning, muting, starring messages, marking chats as read, deleting chats, and deleting individual messages. These operations sync across all your devices via WhatsApp’s app state sync mechanism.
Access
Access chat action operations through the client:Archive
archive_chat
Archive a chat to hide it from the main chat list.jid- The chat JID to archivemessage_range- Optional message range for multi-device conflict resolution. PassNonein most cases
unarchive_chat
Unarchive a chat to show it in the main chat list.jid- The chat JID to unarchivemessage_range- Optional message range for multi-device conflict resolution. PassNonein most cases
Pin
pin_chat
Pin a chat to keep it at the top of the chat list.jid- The chat JID to pin
WhatsApp limits the number of pinned chats. Attempting to pin too many chats may fail.
unpin_chat
Unpin a chat.jid- The chat JID to unpin
Mute
mute_chat
Mute a chat indefinitely.jid- The chat JID to mute
mute_chat_until
Mute a chat until a specific time.jid- The chat JID to mutemute_end_timestamp_ms- Unix timestamp in milliseconds when mute expires (must be in the future)
unmute_chat
Unmute a chat.jid- The chat JID to unmute
Star messages
star_message
Star a message to mark it as important.chat_jid- The chat containing the messageparticipant_jid- For group messages from others, passSome(&sender_jid). For 1-on-1 chats or your own messages, passNonemessage_id- The message ID to starfrom_me- Whether the message was sent by you
unstar_message
Remove the star from a message.star_message.
Example:
Mark chat as read
mark_chat_as_read
Mark a chat as read or unread. This is distinct frommark_as_read (IQ receipts) — it syncs the read/unread state across all linked devices.
jid- The chat JID to markread-trueto mark as read,falseto mark as unreadmessage_range- Optional message range for multi-device conflict resolution. PassNonein most cases
This syncs the read/unread badge across linked devices via app state sync (
regular_low collection). To send read receipts to the sender, use client.mark_as_read() instead.Delete chat
delete_chat
Delete a chat from the chat list across all linked devices.jid- The chat JID to deletedelete_media- Whether to also delete downloaded media filesmessage_range- Optional message range for multi-device conflict resolution. PassNonein most cases
Clear chat
clear_chat
Clear a chat’s messages while keeping the chat itself (WhatsApp Web’s “Clear chat”). Unlikedelete_chat, the chat stays in the list — only its messages are removed. Syncs across all linked devices.
jid- The chat JID to cleardelete_starred- Also remove starred messagesdelete_media- Also remove downloaded media filesmessage_range- Optional message range for multi-device conflict resolution. PassNonein most cases
clearChat action.
Example:
Event::ClearChatUpdate.
Save and remove contacts
save_contact
Save or rename a contact, syncing the name to your other linked devices (WhatsApp Web’s contact-sync action).jid- The contact’s JID. Must be a bare phone-number JID — LIDs and device-specific JIDs are rejected (LID contacts use a separate path on WhatsApp Web).full_name- Full display name, orNonefirst_name- Short name, orNone(omitted when absent; WhatsApp Web derives no default)save_on_primary_addressbook- Whether to save the name to the phone’s address book
remove_contact
Delete a saved contact, syncing the removal to your other linked devices.jid- The contact’s JID. Must be a bare phone-number JID, the same rule assave_contact.
Unlike
save_contact, which writes a Set, remove_contact sends a syncd Remove for the same ["contact", jid] index. WhatsApp Web picks the operation from an isDelete flag when building this mutation. Its receiving side then branches on the operation: a Set with an empty ContactAction gets applied as a rename to the empty string, not a deletion, so only a genuine Remove deletes the contact. WhatsApp Web still builds the action value before choosing the operation, so remove_contact sends an all-default ContactAction alongside the Remove operation.Status mute
set_user_status_mute
Mute or unmute a contact, group, or channel’s status updates across linked devices (WhatsApp Web’suserStatusMute). This is distinct from mute_chat, which silences a chat’s message notifications.
jid- The entity whose status updates to mute/unmutemuted-truehides their status updates,falseunmutes
Event::UserStatusMuteUpdate.
Delete message for me
delete_message_for_me
Delete a specific message locally (not for the other party). This is different fromrevoke_message which deletes for everyone.
chat_jid- The chat containing the messageparticipant_jid- For group messages from others, passSome(&sender_jid). For 1-on-1 chats or your own messages, passNonemessage_id- The ID of the message to deletefrom_me- Whether the message was sent by youdelete_media- Whether to also delete the associated media filemessage_timestamp- Optional timestamp of the message
This only removes the message from your own devices. The other party can still see the message. To delete for everyone, use
client.revoke_message() instead.Helper functions
message_range
Construct aSyncActionMessageRange for multi-device conflict resolution. In most cases you can pass None instead — only WhatsApp Web with a full message database populates this.
message_key
Construct aMessageKey for use with message_range.
Generic app state action
send_app_state_action
Send any syncd (app state)Set action, driven by a generated schema from the whatsapp_rust::schemas registry. Use this as the escape hatch when there isn’t a dedicated helper yet (for example, clear_chat, favorites). Most typed methods on ChatActions, Labels, QuickReplies, and AppStateSettings are thin wrappers over this same call. The one exception is ChatActions::remove_contact, which wraps remove_app_state_action below instead, since contact removal needs a Remove rather than a Set.
schema— A&Schemaconstant fromwhatsapp_rust::schemas(re-exported fromwacore::appstate::schemas). The schema decides the collection, action version, and index shape.index_args— The non-literal index parts in the order declared byschema.index_parts. Literal slots (the action name prefix) are filled automatically.value— Awa::SyncActionValuewith the matching action sub-field set and atimestampin epoch milliseconds.
- The action you need does not have a typed helper on
ChatActions,Labels,QuickReplies, orAppStateSettings. - You need to interoperate with a schema added to the registry without waiting for a new helper to land.
pin_chat, mute_chat, archive_chat, label methods, etc.) whenever they exist — they handle the timestamp, conflict-resolution fields, and index args for you.
Example:
Index arguments are positional and must match
schema.index_parts length and order, excluding IndexPart::Literal slots. Mismatched arity returns an error before any patch is sent.remove_app_state_action
Send an app-state action as a syncdRemove rather than a Set. Sibling of send_app_state_action above, for the small set of actions that model deletion as their own operation instead of a deleted flag inside a Set value.
send_app_state_action — schema, index_args, and value are used identically. Only the wire operation differs.
Example:
App state sync
All chat actions are synced across devices using WhatsApp’s app state synchronization:App state sync requires encryption keys to be available. These are typically obtained during initial sync after authentication. Actions may fail if called immediately after pairing before sync completes.
As of PR #1158, losing an app-state version race no longer silently drops your mutation. A version race happens when another linked device already advanced the same collection. The server now answers with the winning patches instead of an error. The client applies them, rebuilds your mutation on the new base, and resends. It retries up to 5 times, matching WhatsApp Web’s own cap. Previously, the call returned
Ok(()) even though the conflict response was ignored and the mutation never took effect. This conflict-resolution path only returns Err after those 5 attempts are exhausted, or if the server rejects the patch outright (not a version conflict). The other failure causes in Error handling below — invalid input, missing sync keys, network errors — are unrelated to this change and still apply as before.Events
Chat action changes are emitted as events that you can handle:Event::ContactRemoved is distinct from Event::ContactUpdate — see ContactRemoved.
Error handling
All methods returnResult<(), AppStateError>:
InvalidRequest— you passed an invalid timestamp tomute_chat_untilor omittedparticipant_jidfor a group operationInternal— no app state sync key is available yet (sync not complete), a network error occurred, or (as of PR #1158) an app-state version conflict with another device could not be resolved after 5 rebuild-and-resend attempts
Complete example
See also
- Events - Handle chat action update events
- Groups - Group management operations
- Client - Core client API
- Labels - Chat and message label operations built on the same app-state send path
- Quick Replies - Saved reply shortcuts built on the same app-state send path