Skip to main content

Support attachments in your app built with XMTP

Status Status

Use the attachment and remote attachment content types to support attachments in your app. Remote attachments of any size can be sent using the RemoteAttachmentCodec and a storage provider.

Open for feedback

You're welcome to provide feedback by commenting on the Remote Attachment Content Type Proposal XIP.

Configure the content type

In some SDKs, the AttachmentCodec is already included in the SDK. If not, you can install the package using the following command:

In the JavaScript SDK, you need to import this package first.

npm i @xmtp/content-type-remote-attachment

After importing the package, you can register the codec.

import {
} from "@xmtp/content-type-remote-attachment";
// Create the XMTP client
const xmtp = await Client.create(signer, { env: "dev" });
xmtp.registerCodec(new AttachmentCodec());
xmtp.registerCodec(new RemoteAttachmentCodec());

Send a remote attachment

Load the file. This example uses a web browser to load the file:

//image is the uploaded[0];
const data = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
if (reader.result instanceof ArrayBuffer) {
} else {
reject(new Error("Not an ArrayBuffer"));

Create an attachment object:

// Local file details
const attachment = {
filename: image?.name,
mimeType: image?.type,
data: new Uint8Array(data),

Use RemoteAttachmentCodec.encodeEncrypted to encrypt an attachment:

const encryptedEncoded = await RemoteAttachmentCodec.encodeEncrypted(
new AttachmentCodec(),

Upload an encrypted attachment to a location where it will be accessible via an HTTPS GET request. This location will depend on which storage provider you use based on your needs. For example, the example app uses (This information is shared for educational purposes only and is not an endorsement.)

Now that you have a url, you can create a RemoteAttachment:

const remoteAttachment = {
url: url,
contentDigest: encryptedEncoded.digest,
salt: encryptedEncoded.salt,
nonce: encryptedEncoded.nonce,
secret: encryptedEncoded.secret,
scheme: "https://",
filename: attachment.filename,

Now that you have a remote attachment, you can send it:

await conversation.send(remoteAttachment, {
contentType: ContentTypeRemoteAttachment,

Receive, decode, and decrypt a remote attachment

Now that you can receive a remote attachment, you need a way to receive a remote attachment. For example:

import { ContentTypeRemoteAttachment } from "@xmtp/content-type-remote-attachment";

if (message.contentType.sameAs(RemoteAttachmentContentType)) {
const attachment = await RemoteAttachmentCodec.load(message.content, client);

You now have the original attachment:

attachment.filename // => "screenshot.png"
attachment.mimeType // => "image/png", // => [the PNG data]

Once you've created the attachment object, you can create a preview to show in the message input field before sending:

const objectURL = URL.createObjectURL(
new Blob([Buffer.from(], {
type: attachment.mimeType,

const img = document.createElement("img");
img.src = objectURL;
img.title = attachment.filename;

To handle unsupported content types, refer to the fallback section.

Was the information on this page helpful?
powered by XMTP