Skip to content

Support attachments with your agent built with XMTP

Use the remote attachment content type (RemoteAttachmentCodec) and a storage provider to send one remote attachment of any size.

The remote attachment content type is built into the Agent SDK. No installation is required.

Send a remote attachment

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

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

Create an attachment object:

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

Use encryptAttachment to encrypt an attachment:

Node
import { encryptAttachment } from '@xmtp/agent-sdk';
 
const encryptedAttachment = await encryptAttachment(attachment);

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.

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

Node
import type { RemoteAttachment } from '@xmtp/agent-sdk';
 
const remoteAttachment: RemoteAttachment = {
  url: url,
  contentDigest: encryptedAttachment.contentDigest,
  salt: encryptedAttachment.salt,
  nonce: encryptedAttachment.nonce,
  secret: encryptedAttachment.secret,
  scheme: 'https://',
  filename: encryptedAttachment.filename,
  contentLength: encryptedAttachment.contentLength,
};

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

Node
await ctx.conversation.sendRemoteAttachment(remoteAttachment);

Receive, decode, and decrypt a remote attachment

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

Node
import { decryptAttachment } from '@xmtp/agent-sdk';
import type { RemoteAttachment } from '@xmtp/agent-sdk';
 
if (ctx.isRemoteAttachment()) {
  const remoteAttachment: RemoteAttachment = ctx.message.content;
  // Download encrypted bytes from remoteAttachment.url
  const encryptedBytes = await fetch(remoteAttachment.url).then(r => r.arrayBuffer());
  const attachment = await decryptAttachment(
    new Uint8Array(encryptedBytes),
    remoteAttachment
  );
}

You now have the original attachment:

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

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

Node
const objectURL = URL.createObjectURL(
  new Blob([Buffer.from(attachment.data)], {
    type: attachment.mimeType,
  })
);
 
const img = document.createElement('img');
img.src = objectURL;
img.title = attachment.filename;