Presence struct provides methods for managing your online/offline status and subscribing to contact presence updates.
Access
Access presence operations through the client:Methods
set
Set your presence status (online or offline).status: PresenceStatus- EitherAvailable(online) orUnavailable(offline)
- Push name must be set before sending presence
- Returns error if push name is empty
set_available
Convenience method to set status to available (online).set_unavailable
Convenience method to set status to unavailable (offline).subscribe
Subscribe to a contact’s presence updates.jid- Contact JID to subscribe to
- Sends a
<presence type="subscribe">stanza - Automatically includes TC token if available for the contact
- Tracks the subscription internally so it can be restored on reconnect
- Used to receive notifications when the contact goes online/offline
unsubscribe
Unsubscribe from a contact’s presence updates.jid- Contact JID to unsubscribe from
- Sends a
<presence type="unsubscribe">stanza - Removes the contact from the internal subscription tracker
- You will no longer receive presence updates for this contact
PresenceStatus Enum
PresenceStatus is #[non_exhaustive], so match statements should include a wildcard arm to handle future variants.
Methods:
as_str()- Returns"available"or"unavailable"
Push name requirement
WhatsApp requires a push name (display name) to be set before sending presence updates. This matches WhatsApp Web behavior. Error example:Wire Format
Setting Presence
Subscribing to Presence
Unsubscribing from Presence
TC token handling
When subscribing to presence, the library automatically:- Looks up TC token for the target JID
- Includes token as child node if available
- Skips token if not found (non-error)
Subscription Tracking
The library automatically tracks which contacts you have subscribed to. This enables automatic re-subscription after a reconnect, so you don’t lose presence updates when the connection drops.How it works
- Calling
subscribe(jid)adds the contact to an internal tracked set - Calling
unsubscribe(jid)removes the contact from the tracked set - Duplicate subscriptions are deduplicated automatically
- On reconnect, the library re-subscribes to all tracked contacts
Automatic re-subscription on reconnect
When the client reconnects after a connection drop, it automatically callsresubscribe_presence_subscriptions() to restore all tracked presence subscriptions. This happens transparently — you don’t need to manually re-subscribe after a reconnect.
As of whatsapp-rust#1405, the walk is windowed rather than one contact at a time: tracked JIDs are processed 8 at a time (matching the noise sender’s own queue depth), with one get_tc_tokens call per window instead of one lookup per contact, and the window’s <presence type="subscribe"> stanzas issued together so the transport sender can coalesce them into fewer writes. For 24 tracked contacts this is 3 batched calls instead of 24 individual lookups — a backend that hasn’t overridden get_tc_tokens’s default still runs one query per JID underneath each call, but the built-in SqliteStore collapses each window to a single IN (...) query, i.e. 3 DB reads instead of 24. The transport writes only shrink to the extent the sender coalesces the window’s stanzas; the guarantee is fewer writes than one per contact, not a fixed count.
The re-subscription process includes safety checks, now applied per window rather than per JID:
- Bails out early if the connection generation changes (a new reconnect occurred), so a reconnect landing mid-walk stops it within one window rather than after the whole tracked set
- Skips re-subscription if the client is no longer connected
- Re-checks each JID against the tracked set both before and after its window’s tcToken lookup, so an
unsubscriberacing the walk is honored — a JID unsubscribed before its window starts, or while the window’s lookup is in flight, is left out of that window’s sends rather than resubscribed
This matches WhatsApp Web behavior, which re-subscribes to all active presence subscriptions after reconnecting. The per-window (rather than per-JID) safety checks are a narrower guarantee than a strictly per-JID re-check would give, but the batching that motivates it — coalesced backend reads and transport writes — needs a unit wider than one JID to pay off.
Behavior Notes
Available (Online)
When setting status toAvailable, the library automatically:
- Validates push name is set
- Sends unified session (internal protocol requirement)
- Broadcasts presence stanza with push name
Unavailable (Offline)
When setting status toUnavailable:
- Validates push name is set
- Broadcasts unavailable presence
PresenceError
Theset, set_available, and set_unavailable methods return Result<(), PresenceError>:
PushNameEmpty- Push name must be set before sending presenceClient— wraps aClientError(connection errors fromset,set_available,set_unavailable,subscribe, andunsubscribe)Other- Wraps any other error (network, connection, etc.)