Skip to main content

Chat Frames with XMTP

The XMTP community has implemented ways to enhance user experience by supporting frames within XMTP applications by supporting Open Frames. More details in this community post Supporting Frames in XMTP.

Libraries

These are the foundational tools that allow developers to create, sign, and manage Frames created by Open Frames & XMTP

Frameworks

Popular frameworks have already integrated Open Frames into their stack:

OnChainKit

Discover how OnchainKit seamlessly incorporates XMTP payloads

Metadata:

const frameMetadata = getFrameMetadata({
/**
* Frame metadata like Image, Buttons, Input, etc.
*/
isOpenFrame: true,
accepts: { xmtp: "vNext" },
});

export const metadata: Metadata = {
/**
* ...other metadata
*/
other: {
...frameMetadata,
},
};

Validate incoming messages

import {
isXmtpFrameRequest,
getXmtpFrameMessage,
} from "@coinbase/onchainkit/xmtp";
/* ... */
async function getResponse(req: any): Promise<NextResponse> {
const body: FrameRequest = await req.json();
if (isXmtpFrameRequest(body)) {
const { isValid, message } = await getXmtpFrameMessage(body);
// ... do something with the message if isValid is true
if (isValid) {
const { verifiedWalletAddress } = message;
// ... do something with the verifiedWalletAddress
}
} else {
// ...
}
}
  • OnChainKit: Official OnchainKit documentation.
  • Quickstart: Onchainkit quickstart that integrates XMTP.
Frames.js

Learn more about the integration of XMTP payloads within FrameJS

Metadata

const acceptedProtocols: ClientProtocolId[] = [
{
id: "xmtp",
version: "vNext",
},
{
id: "farcaster",
version: "vNext",
},
];

Validate incoming messages:

import { getXmtpFrameMessage, isXmtpFrameActionPayload } from "frames.js/xmtp";

let fid: number | undefined;
let walletAddress: string | undefined;

if (isXmtpFrameActionPayload(previousFrame.postBody)) {
const frameMessage = await getXmtpFrameMessage(previousFrame.postBody);
const { verifiedWalletAddress } = frameMessage;
// Do something with xmtp wallet address
} else {
// Do something else
}
Frog

Metadata

To build a Frame with XMTP, you must first add XMTP metadata.

const addMetaTags = (client: string, version?: string) => {
// Follow the OpenFrames meta tags spec
return {
unstable_metaTags: [
{ property: `of:accepts`, content: version || "vNext" },
{ property: `of:accepts:${client}`, content: version || "vNext" },
],
};
};

export const app = new Frog(addMetaTags("xmtp"));

Validate incoming messages:

Install the @xmtp/frames-validator package to validate incoming messages.

npm install @xmtp/frames-validator

Add the middleware to validate incoming messages.

import { validateFramesPost } from "@xmtp/frames-validator";

const xmtpSupport = async (c: Context, next: Next) => {
// Check if the request is a POST and relevant for XMTP processing
if (c.req.method === "POST") {
const requestBody = (await c.req.json().catch(() => {})) || {};
if (requestBody?.clientProtocol?.includes("xmtp")) {
c.set("client", "xmtp");
const { verifiedWalletAddress } = await validateFramesPost(requestBody);
c.set("verifiedWalletAddress", verifiedWalletAddress);
} else {
// Add farcaster check
c.set("client", "farcaster");
}
}
await next();
};

app.use(xmtpSupport);

Access verified wallet address:

app.frame("/", (c) => {
/* Get Frame variables */
const { buttonValue, inputText, status } = c;

// XMTP verified address
const { verifiedWalletAddress } = c?.var || {};

/* return */
});
  • Frog: XMTP Frog official middleware
  • Quickstart: Frog open frame XMTP quickstart

Tutorials

Clients

Some clients are fully XMTP compatible and can render Frames signing XMTP payloads:

  • Converse: Converse is Frame compatible. Send your Frames through Converse.
  • Dev Inbox: Engage with Frames firsthand by trying them on web.

Was the information on this page helpful?
powered by XMTP