Skip to content

Open Frames: make frames that work everywhere

Open Frames is a standard for Frames that work in multiple ecosystems, including Farcaster, XMTP, Lens and others.

You can define your frame as supporting multiple Open Frames compatible protocols by using the openframes middleware.

// ...
import { openframes } from "frames.js/middleware";
 
const frames = createFrames({
  // ...
  middleware: [
    openframes({
      clientProtocol: {
        id: "my-protocol",
        version: "1.0.0",
      },
      handler: {
        isValidPayload: (body: JSON) => {
          // Check if the request body is a valid Open Frames action
          // ...
          return isValid; // true or false
        },
        getFrameMessage: async (body: JSON) => {
          // Parse the data in the request body and return a Frame message
          // ...
          return frameMessage; // { username: "alice" }
        },
      },
    }),
  ],
});

and access the protocol used to sign the Frame Message via the clientProtocol property of the context.

// ...
const handleRequest = frames(async (ctx) => {
  if (ctx.clientProtocol === "my-protocol") {
    // ctx.username is available here
  }
  // ...
});

Unauthenticated Frames

Open Frames can be used to create unauthenticated Frames that can be supported by all clients by using the anonymous frames convention, which is built into the openframes middleware.

In order to support unauthenticated frames in your application, simply include openframes() without supplying any arguments in your createFrames middleware.

const frames = createFrames({
  // ...
  middleware: [openframes()],
});

This will add of:accepts:anonymous to your page metadata. Clients will then be able to send frame POST requests to your handler without needing to sign the payload. Your frames handler will receive the buttonIndex and optionally inputText and state in the ctx object.

Multi Protocol Example

Here is an example of a multi-protocol createFrames configuration that supports anonymous, XMTP, and Lens protocols.

frames.ts
import { createFrames } from "frames.js/next";
import { openframes } from "frames.js/middleware";
import { getXmtpFrameMessage, isXmtpFrameActionPayload } from "frames.js/xmtp";
import { getLensFrameMessage, isLensFrameActionPayload } from "frames.js/lens";
 
export const frames = createFrames({
  // ...
  middleware: [
    // XMTP
    openframes({
      clientProtocol: {
        id: "xmtp",
        version: "2024-02-09",
      },
      handler: {
        isValidPayload: (body) => isXmtpFrameActionPayload(body),
        getFrameMessage: async (body) => {
          if (!isXmtpFrameActionPayload(body)) {
            return undefined;
          }
          const result = await getXmtpFrameMessage(body);
          return result;
        },
      },
    }),
    // Lens
    openframes({
      clientProtocol: {
        id: "lens",
        version: "1.0.0",
      },
      handler: {
        isValidPayload: (body) => isLensFrameActionPayload(body),
        getFrameMessage: async (body) => {
          if (!isLensFrameActionPayload(body)) {
            return undefined;
          }
          const result = await getLensFrameMessage(body);
          return result;
        },
      },
    }),
    // Anonymous
    openframes(),
  ],
});

See the full example in the Multi Protocol starter template.