Overview
An XMTP client progresses through these stages:- Builder Configuration: Set up API, storage, and identity
- Client Construction: Initialize context and workers
- Identity Registration: Link installation to inbox (if needed)
- Ready State: Client can create/join groups and send messages
- Lifecycle Management: Reconnection, cleanup, and shutdown
Client Architecture
TheClient<Context> is generic over its context:
Context is Arc<XmtpMlsLocalContext<ApiClient, Db, S>> containing:
- Identity and installation keys
- API client for network communication
- Database for state and messages
- MLS storage for cryptographic material
- Smart contract verifier
- Locks and mutexes for concurrency
- Event channels
Building a Client
Identity Strategy
Choose how to handle identity:- Generates installation keys on first run
- Derives inbox ID from wallet + nonce
- Stores identity in database
- Subsequent runs load from database
- For clients that must already exist
- Fails if database doesn’t contain identity
- Useful for re-initializing after disconnect
- Advanced use case
- Manually construct
Identityand pass in - Full control over key generation
Basic Builder Pattern
Configuration Options
API Clients
- api_client: Main network operations (send messages, add members)
- sync_api_client: Background sync operations (pull messages, welcomes)
Storage
- Encrypted SQLite database via
xmtp_db - Stores messages, groups, identity updates, consent
- Stores OpenMLS state (epochs, key packages, ratchet trees)
- Default:
SqlKeyStorebacked by same database - Can provide custom implementation
Use
EncryptedMessageStore::new() or EncryptedMessageStore::new_unencrypted() to create the application store. Encryption key should be securely stored by the application.Smart Contract Verifier
- RemoteSignatureVerifier: Uses XMTP validation service
- ChainRpcVerifier: Validates directly via EVM RPC (requires RPC URLs)
- Custom implementation
Workers
- SyncWorker: Polls for new messages (if device sync enabled)
- KeyPackagesCleanerWorker: Rotates key packages
- DisappearingMessagesWorker: Deletes expired messages
- PendingSelfRemoveWorker: Processes pending member removals
- CommitLogWorker: Publishes commit logs (optional)
Optional Configuration
Full Example
Identity Registration
After building, the client must register its installation with the network.Registration States
The client can be in three states:1. New Inbox (No Previous Registration)
Inbox ID doesn’t exist on network:- Creates inbox on network
- Links wallet and installation to inbox
- Uploads key package
- Publishes identity update
client.identity().is_ready() returns true.
2. Existing Inbox, New Installation
Inbox exists but this installation isn’t registered:Any wallet already linked to the inbox can sign the
AddAssociation action. It doesn’t have to be the original wallet.3. Already Registered
Client installation is already registered:register_identity() is idempotent and returns immediately if already registered.
Registration Flow Details
Insideregister_identity() (from client.rs:875-942):
-
Check if already registered: Query database for
StoredIdentity- If exists, mark ready and return
-
Generate key package: Create MLS key package with installation key
- Store locally (not uploaded yet)
-
Validate signatures: Verify all signatures before network calls
- Prevents polluting network with invalid updates
-
Upload key package: Send to network first
- Prevents race where identity update visible but no key package
- Publish identity update: Make installation visible on network
-
Fetch and store: Download identity updates and store in local DB
- Needed for group operations
- Clean up old key packages: Mark previous packages for deletion
-
Mark identity ready: Set
is_ready()flag
Key Package Management
Rotation
Key packages should be rotated after use:- After receiving a welcome message (key package consumed)
- Periodically (recommended but not enforced)
KeyPackagesCleanerWorker handles rotation based on schedule stored in database.
Manual Queueing
Fetching Key Packages
Get current key packages for installations:Client Operations
Accessing Client Data
Checking Registration Status
IdentityError::UninitializedIdentity if not ready.
Getting Inbox State
Sequence ID
Get current sequence ID for your inbox:Lifecycle Management
Disconnecting Database
Release database connection (useful for mobile):Reconnecting
Reconnect after releasing:Waiting for Workers
Ensure sync worker is initialized:SyncWorker is running and ready.
Sync Operations
Sync Welcomes
Discover new groups:Sync All Groups
Update all existing groups:Error Handling
Common Errors
UninitializedIdentity:register_identity() before performing operations.
Storage Errors:
Retryable Errors
Check if error should be retried:Testing
Test Utilities
Create test clients:Mock Implementations
Offline Testing
Best Practices
Secure Key Storage
Recommendations:- Mobile: Use platform keychain (iOS Keychain, Android Keystore)
- Web: Consider Web Crypto API or secure server-side storage
- Desktop: OS keychain or encrypted file with user password
Worker Management
For production:Error Recovery
Implement retry logic with exponential backoff for transient errors:Database Migration
Diesel handles migrations automatically. On first run:Platform-Specific Considerations
Mobile (iOS/Android)
- Release DB connection when app backgrounds
- Reconnect when app foregrounds
- Use platform keychain for encryption key
- Consider battery impact of sync workers
Web (WASM)
- Use IndexedDB for storage
- Workers run in Web Workers (if supported)
- Consider IndexedDB size limits
- Handle offline scenarios
Node.js
- Use file-based SQLite
- Workers run in Node async runtime
- Consider clustering for multiple clients
Related Concepts
- Architecture - Overall system design
- Identity System - Registration details
- MLS Protocol - Key package lifecycle
- Groups and Conversations - Using the client
