Skip to main content

mark_as_read

Send read receipts for one or more messages. Read receipts inform the sender that you’ve read their message(s). For group messages, you must pass the original sender’s JID as the sender parameter.
message_ids is a borrowed slice &[&str] to avoid per-call allocations — pass &["ID"] or &["ID_1", "ID_2"].
&Jid
required
Chat JID where the messages were received. Can be:
  • Direct message: 15551234567@s.whatsapp.net
  • Group: 120363040237990503@g.us
Option<&Jid>
Message sender JID. Required for group messages, None for direct messages.
  • For DMs: Pass None
  • For groups: Pass the JID of the user who sent the message(s)
&[&str]
required
List of message IDs to mark as read. Can be a single ID or multiple IDs.If empty, this function returns immediately without sending anything.

Example: mark DM as read

Example: mark group message as read

Example: mark multiple messages as read

Read receipts are not sent automatically by the library. You must explicitly call mark_as_read() when you want to notify the sender that messages have been read.
mark_as_read adapts the wire shape to the chat, matching WhatsApp Web. A newsletter read is sent as read-self. A status@broadcast read carries context="status". When the status author is a LID, it also adds peer_participant_pn (the resolved LID→PN). The same call handles all three cases — you don’t pass anything extra.

mark_as_played

Send played receipts for one or more voice notes or video notes. Played receipts tell the sender that you’ve listened to their voice note or watched their video note — they’re the equivalent of “read” for playable media. Call this only after the user has actually played the media; if you just want to acknowledge that the message was opened, use mark_as_read instead.
message_ids is a borrowed slice &[&str], matching mark_as_read.
&Jid
required
Chat JID where the media message was received. Can be a direct message, group, broadcast list, or newsletter JID.
Option<&Jid>
Original sender JID.
  • For DMs: pass None (the participant attribute is dropped on the wire, matching WhatsApp Web).
  • For groups, broadcast lists, and status broadcasts: pass the JID of the user who sent the media.
  • For newsletters: the receipt is sent as played-self; sender is ignored.
&[&str]
required
Message IDs of the voice or video notes to mark as played. The first ID becomes the receipt’s id attribute; any additional IDs are batched into a <list><item/></list> child, the same shape as mark_as_read.If empty, this function returns immediately without sending anything.

Example: mark a DM voice note as played

Example: mark a group voice note as played

Example: mark multiple voice notes as played

Played receipts are not sent automatically — call mark_as_played() from your media player when the user finishes (or starts) playing the audio or video note. The library does not gate this call on the recipient’s read-receipts privacy setting, matching mark_as_read.

send_delivery_receipt (Internal)

Sends a delivery receipt to the sender of a message. This is an internal method called automatically by the library when messages are received. You typically don’t need to call this directly.
&Arc<MessageInfo>
required
Message metadata containing:
  • id - Message ID
  • source.chat - Chat JID
  • source.sender - Sender JID
  • source.is_from_me - Whether this is your own message
  • source.is_group - Whether this is a group message

Behavior

Delivery receipts are automatically sent for all incoming messages except:
  • Your own messages (is_from_me = true)
  • Messages without an ID
  • Status broadcast messages (status@broadcast)
  • Newsletter messages
For group messages, the receipt includes a participant attribute identifying the sender.
Delivery receipts are sent automatically. Unlike other receipt types (e.g., type="read", type="played"), delivery receipts have no type attribute on the wire — delivery is the implicit default. The library omits the type attribute from ack responses to delivery receipts accordingly, since including an explicit type="delivery" would cause <stream:error> disconnections from the server. This is different from read receipts (type="read"), which you send manually with mark_as_read().

Wire format

Internally, delivery receipts pass JID references directly to the .attr() method, avoiding allocations on the hot path:
v0.6 split the to attribute by addressing case. Earlier versions always used info.source.chat, which strips the device byte (to_non_ad). For multi-device LID senders that arrived with from="USER:DEV@lid", the device-less receipt was rejected by the LID server: it replayed the stanza from the offline queue and eventually closed the stream with <stream:error><ack class="message"/></stream:error>. Matching whatsmeow’s buildBaseReceipt (which echoes node.Attrs["from"] verbatim) and WA Web’s sendDeliveryReceiptsAfterDecryption resolves the issue.
Read receipts (mark_as_read) batch multiple message IDs using a <list> child node with <item> elements:

Receipt Types

WhatsApp supports multiple receipt types:
variant
Delivery receipt (type=""). Confirms message was delivered to the recipient’s device. Sent automatically by the library.
variant
Read receipt (type="read"). Confirms message was read by the recipient. Sent manually via mark_as_read().
variant
Read receipt from your own device (type="read-self"). Received when you read a message on another device.
variant
Played receipt (type="played"). Confirms media (audio/video) was played by the recipient.
variant
Played receipt from your own device (type="played-self"). Received when you play media on another device.
variant
Retry receipt (type="retry"). Recipient failed to decrypt the message and is requesting a retry. Automatically handled by the library.
variant
VoIP call encryption re-keying retry receipt (type="enc_rekey_retry"). Sent when a peer fails to decrypt VoIP call encryption data and needs the sender to re-key. Uses an <enc_rekey> child element (with call-creator, call-id, count attributes) instead of the standard <retry> child. Automatically handled by the library.
variant
Sender receipt (type="sender"). Acknowledges message was sent.
variant
Server error receipt (type="server-error"). Message delivery failed on server.

Receipt Events

You can listen for receipt events to track message delivery and read status using the Bot event handler:

Receipt event structure

MessageSource
Source information:
  • chat - Chat JID where the receipt originated
  • sender - JID of the user who sent the receipt
  • is_group - Whether this is from a group
bool
true when the receipt carried the offline attribute. That means it was drained from the server’s offline queue on reconnect rather than delivered live. Use it to tell a backlog of receipts received at login apart from real-time ones.
Vec<String>
List of message IDs this receipt applies to. Usually contains a single ID, but can have multiple.
DateTime<Utc>
When the receipt was received (local time)
ReceiptType
Type of receipt (Delivered, Read, Played, etc.)

Message tracking example

Track message delivery and read status:

Played receipts (media)

For voice notes and video notes, send played receipts with mark_as_played once the user has played the media. Newsletters send played-self; everything else sends played. The wire shape mirrors read receipts:
You can also listen for incoming played receipts via the Event::Receipt event with ReceiptType::Played or ReceiptType::PlayedSelf.

Best Practices

Read receipt privacy

Respect user privacy settings. If you’re building a client, consider adding a setting to disable read receipts.

Batching multiple receipts

Send read receipts for multiple messages at once to reduce network overhead:

Group message receipts

Always include the sender JID for group messages: