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
- @xmtp/frames-validator: A set of tools for validating POST payloads from XMTP Frames
- @xmtp/frames-client: Library used by messaging apps to render xmtp frames.
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
}
- Frames.js: Official Framesjs Documentation.
- Quickstart: Frames.js example that integrates XMTP.
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
- Transaction Frames: Create transactional frames compatible with messaging apps
Clients
Some clients are fully XMTP compatible and can render Frames signing XMTP payloads:
- Converse: Converse is Frame compatible. Send your Frames through Converse.
- Frames Quickstart: Engage with Frames firsthand by trying them on web.