Manage user consent preferences and control unwanted messages in LibXMTP
Consent management allows users to control which conversations and contacts they interact with. This guide covers setting consent preferences, filtering conversations, and handling blocked users.
use xmtp_db::consent_record::ConsentState;pub enum ConsentState { Unknown, // No explicit preference set Allowed, // User has allowed this entity Denied, // User has blocked/denied this entity}
use xmtp_db::consent_record::{ConsentState, ConsentType, StoredConsentRecord};// Allow a conversationlet consent_record = StoredConsentRecord::new( hex::encode(&group.group_id), ConsentType::ConversationId, ConsentState::Allowed,);client.set_consent_states(&[consent_record]).await?;
Or use the group helper:
// Update consent directly on the groupgroup.update_consent_state(ConsentState::Allowed)?;// Check current statelet state = group.consent_state()?;assert_eq!(state, ConsentState::Allowed);
When invited to a group, consent defaults to Unknown:
// User receives a welcome messageclient.sync_welcomes().await?;let groups = client.find_groups(GroupQueryArgs::default())?;for group in groups { let state = group.consent_state()?; if state == ConsentState::Unknown { println!("New invitation - no consent set yet"); }}
use xmtp_db::consent_record::ConsentState;// Only receive messages from allowed conversationslet stream = client.stream_all_messages( None, // conversation_type Some(vec![ConsentState::Allowed]), // consent filter).await?;while let Some(message) = stream.next().await { // Only messages from allowed conversations process_message(message);}
// On device 1: Set consentgroup.update_consent_state(ConsentState::Denied)?;// On device 2: Consent is automatically syncedclient.sync_welcomes().await?;let synced_group = client.group(&group.group_id)?;assert_eq!(synced_group.consent_state()?, ConsentState::Denied);
Consent preferences are synced between your installations via the device sync mechanism. Changes on one device will propagate to other devices.
let groups = client.find_groups( GroupQueryArgs::default() .consent_states(Some(vec![ConsentState::Unknown])))?;for group in groups { let metadata = group.metadata()?; println!("New group: {:?}", metadata.group_name); println!("Added by: {}", group.added_by_inbox_id()?); // Let user decide // group.update_consent_state(ConsentState::Allowed)?; // or // group.update_consent_state(ConsentState::Denied)?;}
4
Block and Leave
5
Block a conversation and optionally leave:
6
// Block the conversationgroup.update_consent_state(ConsentState::Denied)?;// Optionally leave the groupgroup.leave().await?;
7
Unblock
8
Change consent back to allowed:
9
// Unblockgroup.update_consent_state(ConsentState::Allowed)?;// Group messages will now be received
When creating groups for others, consent is already set to allowed:
3
let group = client.create_group(None, None)?;assert_eq!(group.consent_state()?, ConsentState::Allowed);// No need to set consent explicitly
4
Prompt for Consent on Invites
5
When receiving invites, prompt users:
6
let new_groups = client.sync_welcomes().await?;for group in new_groups { if group.consent_state()? == ConsentState::Unknown { let metadata = group.metadata()?; // Show UI to user // "Accept invitation to: {:?}?", metadata.group_name // Based on user choice: // group.update_consent_state(ConsentState::Allowed)?; // or // group.update_consent_state(ConsentState::Denied)?; }}
7
Filter Streams by Consent
8
Always filter message streams to respect user preferences:
9
// Good: Only show allowed messageslet stream = client.stream_all_messages( None, Some(vec![ConsentState::Allowed]),).await?;// Also good: Include unknown for new inviteslet stream = client.stream_all_messages( None, Some(vec![ConsentState::Allowed, ConsentState::Unknown]),).await?;// Avoid: Showing denied conversations// let stream = client.stream_all_messages(None, None).await?;
10
Sync Consent Preferences
11
Ensure consent syncs across devices:
12
// Device sync is enabled by defaultlet client = Client::builder(identity_strategy) .device_sync_worker_mode(DeviceSyncMode::Enabled) // ... other config .build().await?;// Consent changes will sync automatically