Skip to content

Build a chat inbox

Create or build a client

Create an account SigningKey

This code defines two functions that convert different types of Ethereum accounts—Externally Owned Accounts (EOAs) and Smart Contract Wallets (SCWs)—into a unified Signer interface. This ensures that both account types conform to a common interface for message signing and deriving shared secrets as per MLS (Message Layer Security) requirements.

  • For an EOA, the convertEOAToSigner function creates a signer that can get the account address and sign messages and has placeholder methods for wallet type, chain ID, and block number.

    React Native
    // Example EOA
    export function convertEOAToSigner(eoaAccount: EOAAccount): Signer {
      return {
        getAddress: async () => eoaAccount.address,
        signMessage: async (message: string | Uint8Array) =>
          eoaAccount.signMessage({
            message: typeof message === "string" ? message : { raw: message },
          }),
        walletType: () => undefined, // Default: 'EOA'
        getChainId: () => undefined,
        getBlockNumber: () => undefined,
      };
    }
  • For an SCW, the convertSCWToSigner function similarly creates a signer but includes specific implementations for wallet type and chain ID, and an optional block number computation.

    React Native
    // Example SCW
    export function convertSCWToSigner(scwAccount: SCWAccount): Signer {
      return {
        getAddress: async () => scwAccount.address,
        signMessage: async (message: string) => {
          const byteArray = await scwAccount.signMessage(message);
          return ethers.utils.hexlify(byteArray); // Convert to hex string
        },
        walletType: () => "SCW",
        getChainId: async () => 8453, // https://chainlist.org/
        getBlockNumber: async () => undefined, // Optional: will be computed at run
      };
    }

Create an XMTP client

Create an XMTP MLS client that can use the signing capabilities provided by the SigningKey parameter. This SigningKey links the client to the appropriate EOA or SCW.

Node
import { Client } from "@xmtp/node-sdk";
 
const client = await Client.create(alix.address, options /* optional */);

Build an existing client

Build, or resume, an existing client that's logged in and has an existing local database.

React Native
Client.buildV3(address, {
  env: "production", // 'local' | 'dev' | 'production'
  enableV3: true,
  dbEncryptionKey: keyBytes, // 32 bytes
});
 
// Replaces V2 `Client.createFromKeyBundle(bundle)`

Check if an address is reachable

The first step to creating a conversation is to verify that participants’ addresses are reachable on XMTP. The canGroupMessage method checks each address’ compatibility, returning a response indicating whether each address can receive messages.

Once you have the verified addresses, you can create a new conversation, whether it's a group chat or direct message (DM).

Node
import { Client } from "@xmtp/node-sdk";
 
const client = await Client.create(alix.address);
// response is a Map of string (address) => boolean (is reachable)
const response = await client.canMessage([bo.address, caro.address]);

Create a conversation

Create a new group chat

Once you have the verified addresses, create a new group chat:

Node
import { Client } from "@xmtp/node-sdk";
 
const client = await Client.create(alix.address);
const group = await client.conversations.newGroup(
  [bo.address, caro.address],
  createGroupOptions /* optional */
);

Create a new DM

Once you have the verified addresses, create a new DM:

Node
import { Client } from "@xmtp/node-sdk";
 
const client = await Client.create(alix.address, options /* optional */);
const group = await client.conversations.newDm(bo.address);

List conversations and messages

List new group chats or DMs

Get any new group chats or DMs from the network:

Node
import { Client } from "@xmtp/node-sdk";
 
const client = await Client.create(alix.address);
await client.conversations.sync();

List new messages

Get new messages from the network for all existing group chats and DMs in the local database:

Node
import { Client } from "@xmtp/node-sdk";
 
const client = await Client.create(alix.address);
await client.conversations.syncAll();

List existing group chats or DMs

Get a list of existing group chats or DMs in the local database, ordered either by createdAt date or lastMessage.

Node
import { Client } from "@xmtp/node-sdk";
 
const client = await Client.create(alix.address);
const allConversations = await client.conversations.list();
const allGroups = await client.conversations.listGroups();
const allDms = await client.conversations.listDms();

Stream conversations and messages

Stream all group chats and DMs

Listens to the network for new group chats and DMs. Whenever a new conversation starts, it triggers the provided callback function with a ConversationContainer object. This allows the client to immediately respond to any new group chats or DMs initiated by other users.

Node
import { Client } from "@xmtp/node-sdk";
 
const client = await Client.create(alix.address);
const stream = await client.conversations.stream();
// to stream only groups, use `client.conversations.streamGroups()`
// to stream only dms, use `client.conversations.streamDms()`
 
try {
  for await (const conversation of stream) {
    // Received a conversation
  }
} catch (error) {
  // log any stream errors
  console.error(error);
}

Stream all group chat and DM messages

Listens to the network for new messages within all active group chats and DMs. Whenever a new message is sent to any of these conversations, the callback is triggered with a DecodedMessage object. This keeps the inbox up to date by streaming in messages as they arrive.

Node
import { Client } from "@xmtp/node-sdk";
 
const client = await Client.create(alix.address);
const stream = await client.conversations.streamAllMessages();
// to stream only group messages, use `client.conversations.streamAllGroupMessages()`
// to stream only dm messages, use `client.conversations.streamAllDmMessages()`
 
try {
  for await (const message of stream) {
    // Received a message
  }
} catch (error) {
  // log any stream errors
  console.error(error);
}

Helper methods and class interfaces

Conversation helper methods

Use these helper methods to quickly locate and access specific conversations—whether by ID, topic, group ID, or DM address—returning the appropriate ConversationContainer, group, or DM object.

Node
import { Client } from "@xmtp/node-sdk";
 
const client = await Client.create(alix.address);
 
// get a conversation by its ID
const conversationById = await client.conversations.getConversationById(
  conversationId
);
 
// get a message by its ID
const messageById = await client.conversations.getMessageById(messageId);
 
// get a 1:1 conversation by a peer's inbox ID
const dmByInboxId = await client.conversations.getDmByInboxId(peerInboxId);

ConversationContainer interface

Serves as a unified structure for managing both group chats and DMs. It provides a consistent set of properties and methods to seamlessly handle various conversation types.

Group class

Represents a group chat conversation, providing methods to manage group-specific functionalities such as sending messages, synchronizing state, and handling group membership.

Dm class

Represents a DM conversation, providing methods to manage one-on-one communications, such as sending messages, synchronizing state, and handling message streams.