Get started with Open Frames for apps built with XMTP
You can support Frames in apps built with XMTP by using the Open Frames standard. This standard enables you to build a Frame that works in multiple ecosystems, including Farcaster, XMTP, Lens, and others.
This tutorial describes how to display basic, transactional, and subscription Open Frames in an app built with XMTP.
XMTP apps that support Open Frames
These apps built with XMTP can display Open Frames:
- Open Frames quickstart: Test your Open Frames with this quickstart web app
- Converse: Use Open Frames with Converse Messenger
Display basic Open Frames
Use this library to display basic Opens Frames in your app built with XMTP: @xmtp/frames-client
Validate POST payloads from Open Frames
Use these tools to validate create and sign POST payloads from Open Frames used with XMTP: @xmtp/frames-validator
Get started with supporting frameworks
OnchainKit
OnchainKit supports XMTP payloads.
Frame metadata
To build an Open Frame for XMTP, you must first add XMTP metadata:
const frameMetadata = getFrameMetadata({
/**
* Frame metadata like Image, Buttons, Input, etc.
*/
isOpenFrame: true,
accepts: { xmtp: "vNext" },
});
export const metadata: Metadata = {
/**
* ...other metadata
*/
other: {
...frameMetadata,
},
};
How to 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 {
// ...
}
}
Frames.js
Frames.js supports XMTP payloads.
Frame metadata
To build an Open Frame for XMTP, you must first add XMTP metadata:
const acceptedProtocols: ClientProtocolId[] = [
{
id: "xmtp",
version: "vNext",
},
{
id: "farcaster",
version: "vNext",
},
];
How to 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
Frame 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"));
How to validate incoming messages
To validate incoming messages, install the @xmtp/frames-validator
package:
npm install @xmtp/frames-validator
Then add the middleware:
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 a verified wallet address
app.frame("/", (c) => {
/* Get Frame variables */
const { buttonValue, inputText, status } = c;
// XMTP verified address
const { verifiedWalletAddress } = c?.var || {};
/* return */
});