Understand content types with XMTP
When you build an agent with XMTP, all messages are encoded with a content type to ensure that an XMTP client knows how to encode and decode messages, ensuring interoperability and consistent display of messages across apps.
In addition, message payloads are transported as a set of bytes. This means that payloads can carry any content type that a client supports, such as plain text, JSON, or even non-text binary or media content.
At a high level, there are these categories of content types with XMTP:
- Standard
- Custom
Standard content types
A standard content type is one that has undergone the XMTP Request for Comment (XRC) process and has been adopted as an XMTP Improvement Proposal (XIP).
All standard content types are built into the Agent SDK and can be used with dedicated send methods:
- Actions content type: Use
sendActions()to send interactive button prompts. - Group updates content type: Use to send group updates, such as name, description, and members.
- Remote attachment content type: Use
sendRemoteAttachment()to send attachments of any size. - Markdown content type: Use
sendMarkdown()to send rich formatted text messages with headers, lists, tables, and code blocks. - Reaction content type: Use
sendReaction()to send a quick and often emoji-based way to respond to a message. - Reply content type: Use
sendReply()to send a direct response to a specific message in a conversation. Users can select and reply to a particular message instead of sending a new one. - Onchain transaction reference content type: Use
sendTransactionReference()to send references to onchain transactions, such as crypto payments. - Onchain transaction content type: Use
sendWalletSendCalls()to support sending transactions to a wallet for execution.
Custom content types
Custom content types allow you to define your own schemas for messages that go beyond what is covered by standard content types. These are useful for experiments, domain-specific features, or app-specific behaviors.
Writing custom codecs
A content type needs a codec which must satisfy the ContentCodec interface from @xmtp/content-type-primitives.
Example:
import type {
ContentCodec,
ContentTypeId,
EncodedContent,
} from '@xmtp/content-type-primitives';
// Define the content type identifier
export const CustomContentType: ContentTypeId = {
authorityId: 'your-domain.com',
typeId: 'your-custom-id',
versionMajor: 1,
versionMinor: 0,
};
// Implement the codec as a class
export class CustomCodec implements ContentCodec<string> {
contentType = CustomContentType;
encode(content: string): EncodedContent {
return {
type: this.contentType,
parameters: {},
content: new TextEncoder().encode(content),
};
}
decode(content: EncodedContent): string {
return new TextDecoder().decode(content.content);
}
fallback(content: string): string | undefined {
return content;
}
shouldPush(): boolean {
return false;
}
}Registering custom codecs
Pass codec instances to Agent.create():
import { Agent } from '@xmtp/agent-sdk';
const client = await Agent.create(signer, {
codecs: [new CustomCodec()],
});Sending custom content
Encode the content using your codec, then pass the encoded bytes to send():
const codec = new CustomCodec();
await conversation.send(codec.encode('Hello from custom type'));Receiving custom content
The SDK automatically decodes incoming messages using the registered codecs. Access the decoded content via message.content:
const messages = await conversation.messages();
for (const message of messages) {
if (message.type.sameAs(CustomContentType)) {
console.log(message.content); // decoded type
}
}
