Create an XMTP client
Create an XMTP client that can use the signing capabilities provided by the signer. This signer links the client to the appropriate EOA or SCW.
Understand creating and building a client
This video provides a walkthrough of creating and building a client.
How it works
When you call Client.create()
, the following steps happen under the hood:
- Extracts the
signer
and retrieves the wallet address from it. - Checks the XMTP identity ledger to find an inbox ID associated with the signer address. The inbox ID serves as the user's identity on the XMTP network.
- If it doesn't find an existing inbox ID, it requests a wallet signature to register the identity and create an inbox ID.
- If it finds an existing inbox ID, it uses the existing inbox ID.
- Checks if a local SQLite database exists. This database contains the identity's installation state and message data.
- If it doesn't find an existing local database, it creates one and encrypts it with the provided
dbEncryptionKey
. - If it finds an existing local database, it checks to see if the provided
dbEncryptionKey
is a match.- If the
dbEncryptionKey
matches, it uses the existing local database. - If the
dbEncryptionKey
doesn't match, it creates a new local database and encrypts it with the provided key.
- If the
- If it doesn't find an existing local database, it creates one and encrypts it with the provided
- Returns the XMTP client, ready to send and receive messages.

Keep the database encryption key safe
The dbEncryptionKey
is critical to the stability and continuity of an XMTP client. It encrypts the local SQLite database created when you call Client.create()
, and must be provided every time you create or build a client.
As long as the local database and encryption key remain intact, you can use Client.build()
to rehydrate the same client without re-signing.
This encryption key is not stored or persisted by the XMTP SDK, so it's your responsibility as the app developer to store it securely and consistently.
If the encryption key is lost, rotated, or passed incorrectly during a subsequent Client.create()
or Client.build()
call, the app will be unable to access the local database. Likewise, if you initially provided the dbPath
option, you must always provide it with every subsequent call or the client may be unable to access the database. The client will assume that the database can't be decrypted or doesn't exist, and will fall back to creating a new installation.
Creating a new installation requires a new identity registration and signature—and most importantly, results in loss of access to all previously stored messages unless the user has done a history sync.
To ensure seamless app experiences, persist the dbEncryptionKey
securely, and make sure it's available and correctly passed on each app launch.
To learn more about database operations, see the XMTP MLS protocol spec.
Create a client
To call Client.create()
, you must pass in a required signer
and can also pass in any of the optional parameters covered in Configure an XMTP client.
import { Client, type Signer } from "@xmtp/browser-sdk";
// create a signer
const signer: Signer = { /* ... */ };
/**
* The database encryption key is optional but strongly recommended for
* secure local storage of the database.
*
* This value must be consistent when creating a client with an existing
* database.
*/
const dbEncryptionKey = window.crypto.getRandomValues(new Uint8Array(32));
const client = await Client.create(
signer,
// client options
{
dbEncryptionKey,
},
);
Configure an XMTP client
You can configure an XMTP client with these options passed to Client.create
:
import type { ContentCodec } from "@xmtp/content-type-primitives";
type ClientOptions = {
/**
* Specify which XMTP environment to connect to. (default: `dev`)
*/
env?: "local" | "dev" | "production";
/**
* apiUrl can be used to override the `env` flag and connect to a
* specific endpoint
*/
apiUrl?: string;
/**
* historySyncUrl can be used to override the `env` flag and connect to a
* specific endpoint for syncing history
*/
historySyncUrl?: string;
/**
* Allow configuring codecs for additional content types
*/
codecs?: ContentCodec[];
/**
* Path to the local DB
*/
dbPath?: string;
/**
* Encryption key for the local DB
*/
dbEncryptionKey?: Uint8Array;
/**
* Enable structured JSON logging
*/
structuredLogging?: boolean;
/**
* Enable performance metrics
*/
performanceLogging?: boolean;
/**
* Logging level
*/
loggingLevel?: "off" | "error" | "warn" | "info" | "debug" | "trace";
/**
* Disable automatic registration when creating a client
*/
disableAutoRegister?: boolean;
};
XMTP network environments
XMTP provides dev
and production
network environments. These networks are completely separate and not interchangeable.
For example, an XMTP identity on the dev
network is completely distinct from the XMTP identity on the production
network, as are the messages associated with these identities. In addition, XMTP identities and messages created on the dev
network can't be accessed from or moved to the production
network, and vice versa.
The production
network is configured to store messages indefinitely. XMTP may occasionally delete messages and identities from the dev
network, and will provide advance notice in the XMTP Community Forums.
You can also use a local
network to have a client communicate with an XMTP node you are running locally. During development, it's highly recommended to use a local
network environment for speed and reliability.
Build an existing client
Build, or resume, an existing client (created using Client.create()
) that's logged in and has an existing local database.
import { Client, type Identifier } from "@xmtp/browser-sdk";
const identifier: Identifier = {
identifier: "0x1234567890abcdef1234567890abcdef12345678",
identifierKind: "Ethereum",
};
const client = await Client.build(identifier, options);
Log out a client
When you log a user out of your app, you can give them the option to delete their local database.
/**
* The Browser SDK client does not currently support deleting the local database.
*/
// this method only terminates the client's associated web worker
client.close();