Broadcast messages with XMTP
This tutorial will guide you on creating a simple Broadcast that enables the user to broadcast messages to one or many specified Ethereum addresses.
📥 Need a quick reference? Check out this GitHub repo: xmtp-broadcast
Considerations
Before diving into the code let's consider important aspects while integrating consent features. For example, before making an allow or block action you should synchronize the updated consent list in order to prevent overwriting network consent from another app. For more details head to these sections of our docs:
- Understand user consent preferences: This section provides a comprehensive understanding of how user consent preferences are set, including but not limited to, direct actions within the app, settings adjustments, and responses to prompts.
- Use consent preferences to respect user intent: Your app should aim to handle consent preferences appropriately because they are an expression of user intent.
- Synchronize user consent preferences:All apps that use the user consent feature must adhere to the logic described in this section to keep the consent list on the network synchronized with local app user consent preferences, and vice versa.
Tutorial
Import the XMTP client and ethers libraries
The code starts by importing the required XMTP and Ethereum packages. This enables you to create an XMTP client and interact with the Ethereum blockchain.
import { Client } from "@xmtp/xmtp-js";
import { ethers } from "ethers";
Set up the walletAddresses
array
The Broadcast function accepts a walletAddresses array. This array holds the Ethereum addresses that you intend to broadcast messages to.
const walletAddresses = [
"0x93E2fc3e99dFb1238eB9e0eF2580EFC5809C7204",
"0xa64af7F78DE39A238Ecd4ffF7D6D410DBACe2dF0",
];
Rate limiting
Keep in mind that the XMTP client limits up to 1,000 publish requests per 5 minutes. It's important to be aware of this when broadcasting messages, especially when dealing with a large array of wallet addresses.
For more information, see the FAQs
Check which addresses can receive messages
In the handleBroadcastClick
function, the canMessage
method checks which wallet addresses from the array can receive messages.
// Create a new XMTP client with the signer and environment
const xmtp = await Client.create(signer, { env: env });
// Check if the client can message the provided wallet addresses
const broadcasts_canMessage = await xmtp.canMessage([walletAddresses]);
This will return an array of booleans that correspond to the wallet addresses. If the boolean is true, the address can receive messages. If the boolean is false, the address cannot receive messages.
Check if address has given consent to the sender
The isAllowed
method checks if the wallet address has given consent to the sender. If the address has not given consent, the sender cannot send messages to the address.
xmtp.contacts.isAllowed(wallet);
Refresh the consent list
To ensure you're working with the most up-to-date information, refresh the consent list before doing the broadcast.
await xmtp.contacts.refreshConsentList();
Loop through wallet address array to broadcast
Loop through the walletAddresses
array. For each address that can receive messages, a new conversation is started, and the message is sent.
// Create a new XMTP client with the signer and environment
const xmtp = await Client.create(signer, { env: env });
// Check if the client can message the provided wallet addresses
const broadcasts_canMessage = await xmtp.canMessage(walletAddresses);
//Update consent list
await xmtp.contacts.refreshConsentList();
// Loop through the wallet addresses
for (let i = 0; i < walletAddresses.length; i++) {
const wallet = walletAddresses[i];
const canMessage = broadcasts_canMessage[i];
// If the address can receive messages and has allowed consent
if (canMessage && xmtp.contacts.isAllowed(wallet)) {
// Create a new conversation with the wallet address
const conversation = await xmtp.conversations.newConversation(wallet);
// Send the broadcast message to the conversation
const sent = await conversation.send(broadcastMessage);
// If a callback function is provided, call it with the sent message
if (onMessageSuccess) {
onMessageSuccess(sent);
}
}
}
Popup UI
A modal pops up when the user opts to send a message. This modal contains a text area for the user to input their message.
{
showPopup && (
<div style={styles.ubContainer}>
<textarea
style={styles.textArea}
placeholder={placeholderMessage}
value={broadcastMessage}
onChange={(e) => setBroadcastMessage(e.target.value)}
disabled={loading}
/>
</div>
);
}
Always synchronize consent states: Before updating consent preferences on the network, ensure you refresh the consent list with refreshConsentList
. Update the network's consent list only in these scenarios:
- User Denies Contact: Set to
denied
if a user blocks or unsubscribes. - User Allows Contact: Set to
allowed
if a user subscribes or enables notifications. - Legacy Preferences: Align the network with any existing local preferences.
- User Response: Set to
allowed
if the user has engaged in conversation.
Neglecting these guidelines can result in consent state conflicts and compromise user privacy.
Conclusion
Consent has really evolved through the years. It started with email, then email marketing, and was the wild west until laws like GPDR stepped in. This is new chapter in the history of consent in a new era for privacy, portability, and ownership.
Example repo
You can find a complete example of this tutorial in the xmtp-broadcast repo.