XMTP Support
Cross-protocol frames are supported by frames.js via familiar APIs. This guide will showcase how to write a simple stateless frame, which returns the identity of the user that interacted with the frame in Farcaster or a XMTP chat.
Steps
Create a new project
Create a new Next.js based Frames app
npx create-next-app@latest my-project --ts --eslint --tailwind --app
cd my-project
Add frames.js
to your project
npm
npm install frames.js
Create your Frames app
Create a frames
directory in your Next.js app
directory and add the following file:
./app/frames/frames.ts
import { openframes } from "frames.js/middleware";
import { createFrames } from "frames.js/next";
import { getXmtpFrameMessage, isXmtpFrameActionPayload } from "frames.js/xmtp";
export const frames = createFrames({
// basePath must point to the route of initial frame
// in this case it will reside in app/frames/route.tsx therefore /frames
basePath: "/frames",
middleware: [
openframes({
clientProtocol: {
id: "xmtp",
version: "2024-02-09",
},
handler: {
isValidPayload: (body) => isXmtpFrameActionPayload(body),
getFrameMessage: async (body) => {
if (!isXmtpFrameActionPayload(body)) {
return undefined;
}
return getXmtpFrameMessage(body);
},
},
}),
],
});
Your Frames app by default always supports Farcaster, now you also added XMTP support.
Create a route
Create following file:
./app/frames/route.tsx
/* eslint-disable react/jsx-key */
import { Button } from "frames.js/next";
import { frames } from "./frames";
const handleRequest = frames(async (ctx) => {
let iAm: string | undefined;
if (ctx.message) {
iAm = (await ctx.message.walletAddress()) ?? "anonymous";
}
return {
image: <span>{iAm ? `I am ${iAm}` : `Click the button`}</span>,
buttons: [<Button action="post">Who am I?</Button>],
};
});
export const GET = handleRequest;
export const POST = handleRequest;
If you have an existing page, render Frames in your metadata
./app/page.tsx
import { fetchMetadata } from "frames.js/next";
export async function generateMetadata() {
return {
title: "My Page",
// provide a full URL to your /frames endpoint
other: await fetchMetadata(
new URL(
"/frames",
process.env.VERCEL_URL
? `https://${process.env.VERCEL_URL}`
: "http://localhost:3000"
)
),
};
}
export default function Page() {
return <span>My existing page</span>;
}
Run
npm
npm run dev