The Presence struct provides methods for managing your online/offline status and subscribing to contact presence updates.
Access
Access presence operations through the client:
let presence = client.presence();
Methods
set
Set your presence status (online or offline).
pub async fn set(&self, status: PresenceStatus) -> Result<(), PresenceError>
Parameters:
status: PresenceStatus - Either Available (online) or Unavailable (offline)
Requirements:
- Push name must be set before sending presence
- Returns error if push name is empty
Example:
use whatsapp_rust::features::presence::PresenceStatus;
// Set status to online
client.presence().set(PresenceStatus::Available).await?;
// Set status to offline
client.presence().set(PresenceStatus::Unavailable).await?;
set_available
Convenience method to set status to available (online).
pub async fn set_available(&self) -> Result<(), PresenceError>
Example:
client.presence().set_available().await?;
println!("Now online");
set_unavailable
Convenience method to set status to unavailable (offline).
pub async fn set_unavailable(&self) -> Result<(), PresenceError>
Example:
client.presence().set_unavailable().await?;
println!("Now offline");
subscribe
Subscribe to a contact’s presence updates.
pub async fn subscribe(&self, jid: &Jid) -> Result<(), anyhow::Error>
Parameters:
jid - Contact JID to subscribe to
Behavior:
- 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
Example:
let contact_jid: Jid = "15551234567@s.whatsapp.net".parse()?;
client.presence().subscribe(&contact_jid).await?;
println!("Subscribed to {}'s presence", contact_jid);
unsubscribe
Unsubscribe from a contact’s presence updates.
pub async fn unsubscribe(&self, jid: &Jid) -> Result<(), anyhow::Error>
Parameters:
jid - Contact JID to unsubscribe from
Behavior:
- Sends a
<presence type="unsubscribe"> stanza
- Removes the contact from the internal subscription tracker
- You will no longer receive presence updates for this contact
Example:
let contact_jid: Jid = "15551234567@s.whatsapp.net".parse()?;
client.presence().unsubscribe(&contact_jid).await?;
println!("Unsubscribed from {}'s presence", contact_jid);
PresenceStatus Enum
#[non_exhaustive]
pub enum PresenceStatus {
Available, // Online
Unavailable, // Offline
}
PresenceStatus is #[non_exhaustive], so match statements should include a wildcard arm to handle future variants.
Methods:
as_str() - Returns "available" or "unavailable"
Conversion:
let status = PresenceStatus::Available;
assert_eq!(status.as_str(), "available");
Push Name Requirement
WhatsApp requires a push name (display name) to be set before sending presence updates. This matches WhatsApp Web behavior.
Error example:
use whatsapp_rust::features::presence::PresenceError;
// If push name not set
match client.presence().set_available().await {
Ok(_) => println!("Presence set"),
Err(PresenceError::PushNameEmpty) => {
eprintln!("Cannot send presence without a push name set");
}
Err(e) => eprintln!("Other error: {}", e),
}
The push name is typically set during the pairing/connection process from app state sync.
Setting Presence
<!-- Available (online) -->
<presence type="available" name="YourPushName"/>
<!-- Unavailable (offline) -->
<presence type="unavailable" name="YourPushName"/>
Subscribing to Presence
<!-- Without TC token -->
<presence type="subscribe" to="15551234567@s.whatsapp.net"/>
<!-- With TC token (privacy gating) -->
<presence type="subscribe" to="15551234567@s.whatsapp.net">
<tctoken><!-- raw token bytes --></tctoken>
</presence>
Unsubscribing from Presence
<presence type="unsubscribe" to="15551234567@s.whatsapp.net"/>
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)
This matches WhatsApp Web’s privacy gating behavior.
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 calls resubscribe_presence_subscriptions() to restore all tracked presence subscriptions. This happens transparently — you don’t need to manually re-subscribe after a reconnect.
The re-subscription process includes safety checks:
- Bails out early if the connection generation changes (a new reconnect occurred)
- Skips re-subscription if the client is no longer connected
This matches WhatsApp Web behavior, which re-subscribes to all active presence subscriptions after reconnecting.
Behavior Notes
Available (Online)
When setting status to Available, 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 to Unavailable:
- Validates push name is set
- Broadcasts unavailable presence
Note: This marks you as offline but doesn’t disconnect the client.
PresenceError
The set, set_available, and set_unavailable methods return Result<(), PresenceError>:
#[derive(Debug, Error)]
pub enum PresenceError {
#[error("cannot send presence without a push name set")]
PushNameEmpty,
#[error(transparent)]
Other(#[from] anyhow::Error),
}
Variants:
PushNameEmpty - Push name must be set before sending presence
Other - Wraps any other error (network, connection, etc.)
Error handling
use whatsapp_rust::features::presence::PresenceError;
match client.presence().set_available().await {
Ok(_) => println!("Successfully set to online"),
Err(PresenceError::PushNameEmpty) => {
eprintln!("Need to set push name first");
}
Err(e) => eprintln!("Unexpected error: {}", e),
}
The subscribe and unsubscribe methods return Result<(), anyhow::Error>.
Complete Example
use whatsapp_rust::features::presence::PresenceStatus;
// Set yourself online
client.presence().set_available().await?;
// Subscribe to contacts' presence
let contacts: Vec<Jid> = vec![
"15551111111@s.whatsapp.net".parse()?,
"15552222222@s.whatsapp.net".parse()?,
];
for contact in &contacts {
client.presence().subscribe(contact).await?;
println!("Subscribed to {}", contact);
}
// Do work while online...
// If the connection drops, tracked subscriptions are
// automatically re-subscribed on reconnect.
// Unsubscribe from a specific contact
client.presence().unsubscribe(&contacts[0]).await?;
println!("Unsubscribed from {}", contacts[0]);
// Set yourself offline when done
client.presence().set_unavailable().await?;
Receiving Presence Updates
After subscribing to a contact’s presence, you’ll receive presence events through the event handler. See the Events documentation for details on handling incoming presence updates.