|
| 1 | +--- |
| 2 | +xip: 58 |
| 3 | +title: Disappearing messages |
| 4 | +description: Proposal to support disappearing messages that are intended to be visible to users for only a short period of time. |
| 5 | +author: Mojtaba Chenani (@mchenani) |
| 6 | +discussions-to: https://community.xmtp.org/t/xip-57-disappearing-messages/888 |
| 7 | +status: Draft |
| 8 | +type: Standards |
| 9 | +category: XRC |
| 10 | +created: 2025-02-13 |
| 11 | +--- |
| 12 | + |
| 13 | +## Abstract |
| 14 | + |
| 15 | +Disappearing messages are messages that are intended to be visible to users for only a short period of time. After the message expiration time passes, the messages are removed from the UI and deleted from local storage so the messages are no longer accessible to conversation participants. |
| 16 | + |
| 17 | +## Motivation |
| 18 | + |
| 19 | +As a modern messaging protocol, XMTP must support disappearing messages—a feature that users and app developers increasingly expect as standard in secure and private communication platforms. Ephemeral messaging has evolved from a novel feature to an essential capability that allows users to maintain control over their digital footprint. This aligns with XMTP's commitment to privacy and security, complementing the protocol's existing encryption and security measures provided through XMTP and MLS. |
| 20 | + |
| 21 | +## Specification |
| 22 | + |
| 23 | +Disappearing message behavior will enforced by apps, meaning that apps are responsible for removing messages from their UIs and local storage based on conditions set at the conversation level. Conversation participants using apps that support disappearing messages will have a UX that honors the message expiration conditions. |
| 24 | + |
| 25 | +It's important to understand that: |
| 26 | + |
| 27 | +- A conversation participant using an app that doesn't support disappearing messages won't experience disappearing message behavior. |
| 28 | +- Messages aren't deleted from the XMTP network. |
| 29 | + |
| 30 | +Therefore, disappearing messages should be understood as best-effort, app-level privacy that helps avoid leaving an easily accessible record in a messaging UI. However, it's not a guaranteed, system-wide “message self-destruct.” |
| 31 | + |
| 32 | +### Enable disappearing messages for a conversation |
| 33 | + |
| 34 | +When creating or updating a conversation, only group admins and DM participants will be able to set disappearing message expiration conditions. |
| 35 | + |
| 36 | +This includes setting the following conditions expressed in nanoseconds (ns): |
| 37 | + |
| 38 | +- `disappearStartingAtNs`: Starting timestamp from which the message lifespan is calculated |
| 39 | +- `retentionDurationInNs`: Duration of time during which the message should remain visible to conversation participants |
| 40 | + |
| 41 | +For example: |
| 42 | + |
| 43 | +1. Set `disappearStartingAtNs` to the current time, such as `1738620126404999936` (nanoseconds since the Unix epoch of January 1, 1970). |
| 44 | +2. Set `retentionDurationInNs` to the message lifespan, such as 1800000000000000 (30 minutes). |
| 45 | +3. Use `disappearStartingAtNs` and `retentionDurationInNs` to calculate the message expiration time of `1738620126404999936 + 1800000000000000 = 1740420126404999936`. |
| 46 | + |
| 47 | +### Set disappearing message setting on conversation create |
| 48 | + |
| 49 | +When sending a message, it abides by message expiration conditions set for the conversation. For example: |
| 50 | + |
| 51 | +```tsx |
| 52 | +// DM |
| 53 | +await client.conversations.newConversation( |
| 54 | + address, |
| 55 | + { |
| 56 | + disappearingMessageSettings: DisappearingMessageSettings( |
| 57 | + disappearStartingAtNs: 1738620126404999936, |
| 58 | + retentionDurationInNs: 1800000000000000 |
| 59 | + ) |
| 60 | + } |
| 61 | +); |
| 62 | + |
| 63 | +// Group |
| 64 | +await client.conversations.newGroup( |
| 65 | + [address], |
| 66 | + { |
| 67 | + disappearingMessageSettings: DisappearingMessageSettings( |
| 68 | + disappearStartingAtNs: 1738620126404999936, |
| 69 | + retentionDurationInNs: 1800000000000000 |
| 70 | + ) |
| 71 | + } |
| 72 | +); |
| 73 | +``` |
| 74 | + |
| 75 | +### Update disappearing message setting on an existing conversation |
| 76 | + |
| 77 | +When sending a message, it will abide by message expiration conditions set for the conversation. For example: |
| 78 | + |
| 79 | +```tsx |
| 80 | +await conversation.updateDisappearingMessageSettings(updatedSettings) |
| 81 | +await conversation.clearDisappearingMessageSettings() |
| 82 | +``` |
| 83 | + |
| 84 | +### Get a conversation’s disappearing message setting |
| 85 | + |
| 86 | +When sending a message, it will abide by message expiration conditions set for the conversation. For example: |
| 87 | + |
| 88 | +```tsx |
| 89 | +conversation.disappearingMessageSettings |
| 90 | +conversation.isDisappearingMessagesEnabled() |
| 91 | +``` |
| 92 | + |
| 93 | +### Automatic deletion from local storage |
| 94 | + |
| 95 | +A background worker will run every one second to clean up expired disappearing messages. The worker will automatically delete expired messages from local storage. No additional action will be required by integrators. |
| 96 | + |
| 97 | +### Automatic removal from UI |
| 98 | + |
| 99 | +Expired messages won’t require manual removal from the UI. If an app UI updates when the local storage changes, expired messages will disappear automatically when the background worker deletes them from local storage. |
| 100 | + |
| 101 | +### Receive a disappearing message |
| 102 | + |
| 103 | +On the receiving side, an app doesn't need to check expiration conditions manually. It can receive and process messages as usual, and the background worker will handle message expiration cleanup. |
| 104 | + |
| 105 | +## Rationale |
| 106 | + |
| 107 | +Some users, depending on their needs, want disappearing messages in a group or one-on-one conversation to ensure messages don’t linger longer than expected on other participants’ devices. Enabling this feature provides a way for users to enforce message expiration, knowing that as long as all clients are updated and functioning correctly, the messages will be automatically removed from those clients. |
| 108 | + |
| 109 | +## Backward compatibility |
| 110 | + |
| 111 | +Since older clients can’t process the new metadata changes, messages won’t be deleted from those clients. Also, those clients won’t recognize that disappearing messages are enabled. This means they will continue sending and displaying messages normally, but for users with updated clients, those messages will be deleted based on the expiration settings—without the sender necessarily being aware that their messages have disappeared. |
| 112 | + |
| 113 | +## Test cases |
| 114 | + |
| 115 | +See tests in [mls.rs](https://github.com/xmtp/libxmtp/blob/8771b149338fba17dd0e1fb97f6eb11bc7ba6491/bindings_ffi/src/mls.rs#L5200-L5453) in the libxmtp repo. |
| 116 | + |
| 117 | +## Reference implementation |
| 118 | + |
| 119 | +See [conversation.rs](https://github.com/xmtp/libxmtp/blob/main/bindings_node/src/conversation.rs#L698). |
| 120 | + |
| 121 | +To learn more about the background worker, see [disappearing_messages.rs](https://github.com/xmtp/libxmtp/blob/main/xmtp_mls/src/groups/disappearing_messages.rs#L68). |
| 122 | + |
| 123 | +## Security considerations |
| 124 | + |
| 125 | +### Threat model |
| 126 | + |
| 127 | +A malicious but updated client could still prevent messages from being deleted on their side. They would receive the disappearing message along with the expiration settings but could modify or build a custom client that ignores the deletion process and retains expired messages. |
| 128 | + |
| 129 | +However, this isn’t a major concern because, ultimately, a recipient can always copy and store a message manually if they choose to. Disappearing messages are more about reducing accessibility and limiting exposure rather than providing absolute protection against message retention. |
| 130 | + |
| 131 | +## Copyright |
| 132 | + |
| 133 | +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). |
0 commit comments