diff --git a/README.md b/README.md
index 5d996f3e56..d2b4688fab 100644
--- a/README.md
+++ b/README.md
@@ -54,11 +54,11 @@ For documentation and guides, visit [onchainkit.xyz](https://onchainkit.xyz/).
- [Frame Kit](https://onchainkit.xyz/framekit/introduction)
- Components:
- - [``](https://onchainkit.xyz/framekit/introduction#framemetadata-)
+ - [``](https://onchainkit.xyz/framekit/frame-metadata)
- Utilities:
- - [`getFrameHtmlResponse`](https://onchainkit.xyz/framekit/introduction#getframehtmlresponseframemetadata)
- - [`getFrameMessage`](https://onchainkit.xyz/framekit/introduction#getframemessageframerequest)
- - [`getFrameMetadata`](https://onchainkit.xyz/framekit/introduction#getframemetadataframemetadata)
+ - [`getFrameHtmlResponse`](https://onchainkit.xyz/framekit/get-frame-html-response)
+ - [`getFrameMessage`](https://onchainkit.xyz/framekit/get-frame-message)
+ - [`getFrameMetadata`](https://onchainkit.xyz/framekit/get-frame-metadata)
- [Identity Kit](https://onchainkit.xyz/identitykit/introduction)
- Components:
diff --git a/site/.yarn/install-state.gz b/site/.yarn/install-state.gz
index 8e9efe360f..58566b7fa2 100644
Binary files a/site/.yarn/install-state.gz and b/site/.yarn/install-state.gz differ
diff --git a/site/docs/pages/framekit/frame-metadata.mdx b/site/docs/pages/framekit/frame-metadata.mdx
new file mode 100644
index 0000000000..7f8270451f
--- /dev/null
+++ b/site/docs/pages/framekit/frame-metadata.mdx
@@ -0,0 +1,97 @@
+# ``
+
+This component is utilized for incorporating Frame metadata elements into the React page.
+
+Note: If you are using Next.js with App routing, it is recommended to use `getFrameMetadata` instead.
+
+## Usage
+
+```tsx
+export default function HomePage() {
+ return (
+ ...
+
+ ...
+ );
+}
+```
+
+## Returns
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Props
+
+```ts
+type FrameButtonMetadata =
+ | {
+ action: 'link' | 'mint';
+ label: string;
+ target: string;
+ }
+ | {
+ action?: 'post' | 'post_redirect';
+ label: string;
+ };
+
+type FrameImageMetadata = {
+ src: string;
+ aspectRatio?: '1.91:1' | '1:1';
+};
+
+type FrameInputMetadata = {
+ text: string;
+};
+
+type FrameMetadataType = {
+ // A list of strings which are the label for the buttons in the frame (max 4 buttons).
+ buttons?: [FrameButtonMetadata, ...FrameButtonMetadata[]];
+ // An image which must be smaller than 10MB and should have an aspect ratio of 1.91:1 or 1:1
+ image: FrameImageMetadata;
+ // The text input to use for the Frame.
+ input?: FrameInputMetadata;
+ // A valid POST URL to send the Signature Packet to.
+ postUrl?: string;
+ // A period in seconds at which the app should expect the image to update.
+ refreshPeriod?: number;
+};
+
+type FrameMetadataReact = FrameMetadataType & {
+ wrapper?: React.ComponentType;
+};
+```
diff --git a/site/docs/pages/framekit/get-frame-html-response.mdx b/site/docs/pages/framekit/get-frame-html-response.mdx
new file mode 100644
index 0000000000..f9215c95a2
--- /dev/null
+++ b/site/docs/pages/framekit/get-frame-html-response.mdx
@@ -0,0 +1,78 @@
+# getFrameHtmlResponse
+
+When you need to send an HTML Frame Response, the `getFrameHtmlResponse` method is here to assist you.
+
+It generates a valid HTML string response with a frame and utilizes `FrameMetadata` types for page metadata. This eliminates the need to manually create server-side HTML strings.
+
+## Usage
+
+```ts
+// Step 1. import getFrameHtmlResponse from @coinbase/onchainkit
+import { getFrameHtmlResponse } from '@coinbase/onchainkit';
+import { NextRequest, NextResponse } from 'next/server';
+
+async function getResponse(req: NextRequest): Promise {
+ // Step 2. Build your Frame logic
+ ...
+
+ return new NextResponse(
+ // Step 3. Use getFrameHtmlResponse to create a Frame response
+ getFrameHtmlResponse({
+ buttons: [
+ {
+ label: `We love BOAT`,
+ },
+ ],
+ image: 'https://build-onchain-apps.vercel.app/release/v-0-17.png',
+ postUrl: 'https://build-onchain-apps.vercel.app/api/frame',
+ }),
+ );
+}
+
+export async function POST(req: NextRequest): Promise {
+ return getResponse(req);
+}
+```
+
+## Returns
+
+```ts
+type FrameHTMLResponse = string;
+```
+
+## Parameters
+
+```ts
+type FrameButtonMetadata =
+ | {
+ action: 'link' | 'mint';
+ label: string;
+ target: string;
+ }
+ | {
+ action?: 'post' | 'post_redirect';
+ label: string;
+ };
+
+type FrameImageMetadata = {
+ src: string;
+ aspectRatio?: '1.91:1' | '1:1';
+};
+
+type FrameInputMetadata = {
+ text: string;
+};
+
+type FrameMetadataType = {
+ // A list of strings which are the label for the buttons in the frame (max 4 buttons).
+ buttons?: [FrameButtonMetadata, ...FrameButtonMetadata[]];
+ // An image which must be smaller than 10MB and should have an aspect ratio of 1.91:1 or 1:1
+ image: FrameImageMetadata;
+ // The text input to use for the Frame.
+ input?: FrameInputMetadata;
+ // A valid POST URL to send the Signature Packet to.
+ postUrl?: string;
+ // A period in seconds at which the app should expect the image to update.
+ refreshPeriod?: number;
+};
+```
diff --git a/site/docs/pages/framekit/get-frame-message.mdx b/site/docs/pages/framekit/get-frame-message.mdx
new file mode 100644
index 0000000000..90a65c07a7
--- /dev/null
+++ b/site/docs/pages/framekit/get-frame-message.mdx
@@ -0,0 +1,90 @@
+# getFrameMessage
+
+When a user interacts with your Frame, you receive a JSON message called the "Frame Signature Packet". Decode and validate this message using the `getFrameMessage` function.
+
+You can also use `getFrameMessage` to access useful information such as:
+
+- button: number
+- fid: number
+- following: boolean
+- liked: boolean
+- recasted: boolean
+- verified_accounts: string[]
+
+Note that if the `message` is not valid, it will be undefined.
+
+## Usage
+
+```ts
+// Step 1. import getFrameMessage from @coinbase/onchainkit
+import { FrameRequest, getFrameMessage } from '@coinbase/onchainkit';
+import { NextRequest, NextResponse } from 'next/server';
+
+async function getResponse(req: NextRequest): Promise {
+ // Step 2. Read the body from the Next Request
+ const body: FrameRequest = await req.json();
+ // Step 3. Validate the message
+ const { isValid, message } = await getFrameMessage(body , {
+ neynarApiKey: 'NEYNAR_ONCHAIN_KIT'
+ });
+
+ // Step 4. Determine the experience based on the validity of the message
+ if (isValid) {
+ // the message is valid
+ } else {
+ // sorry, the message is not valid and it will be undefined
+ }
+
+ ...
+}
+
+export async function POST(req: NextRequest): Promise {
+ return getResponse(req);
+}
+```
+
+## Returns
+
+```ts
+type Promise;
+
+type FrameValidationResponse =
+ | { isValid: true; message: FrameValidationData }
+ | { isValid: false; message: undefined };
+
+interface FrameValidationData {
+ button: number; // Number of the button clicked
+ following: boolean; // Indicates if the viewer clicking the frame follows the cast author
+ input: string; // Text input from the viewer typing in the frame
+ interactor: {
+ fid: number; // Viewer Farcaster ID
+ custody_address: string; // Viewer custody address
+ verified_accounts: string[]; // Viewer account addresses
+ };
+ liked: boolean; // Indicates if the viewer clicking the frame liked the cast
+ raw: NeynarFrameValidationInternalModel;
+ recasted: boolean; // Indicates if the viewer clicking the frame recasted the cast
+ valid: boolean; // Indicates if the frame is valid
+}
+```
+
+## Parameters
+
+```ts
+// The Frame Signature Packet body
+type FrameMessage = {
+ body: FrameRequest;
+ messageOptions?: FrameMessageOptions;
+};
+
+type FrameMessageOptions =
+ | {
+ // The API key to use for validation. Default: NEYNAR_ONCHAIN_KIT
+ neynarApiKey?: string;
+ // Whether to cast the reaction context. Default: true
+ castReactionContext?: boolean;
+ // Whether to follow the context. Default: true
+ followContext?: boolean;
+ }
+ | undefined;
+```
diff --git a/site/docs/pages/framekit/get-frame-metadata.mdx b/site/docs/pages/framekit/get-frame-metadata.mdx
new file mode 100644
index 0000000000..1cace996c4
--- /dev/null
+++ b/site/docs/pages/framekit/get-frame-metadata.mdx
@@ -0,0 +1,78 @@
+# getFrameMetadata
+
+With Next.js App routing, use the `getFrameMetadata()` inside your `page.ts` to get the metadata need it for your Frame.
+
+## Usage
+
+```ts
+// Step 1. import getFrameMetadata from @coinbase/onchainkit
+import { getFrameMetadata } from '@coinbase/onchainkit';
+import type { Metadata } from 'next';
+import HomePage from './home';
+
+// Step 2. Use getFrameMetadata to shape your Frame metadata
+const frameMetadata = getFrameMetadata({
+ buttons: [
+ {
+ label: 'We love BOAT',
+ },
+ ],
+ image: 'https://build-onchain-apps.vercel.app/release/v-0-17.png',
+ postUrl: 'https://build-onchain-apps.vercel.app/api/frame',
+});
+
+// Step 3. Add your metadata in the Next.js metadata utility
+export const metadata: Metadata = {
+ manifest: '/manifest.json',
+ other: {
+ ...frameMetadata
+ },
+};
+
+export default function Page() {
+ return ;
+}
+```
+
+## Returns
+
+```ts
+type FrameMetadataResponse = Record;
+```
+
+## Parameters
+
+```ts
+type FrameButtonMetadata =
+ | {
+ action: 'link' | 'mint';
+ label: string;
+ target: string;
+ }
+ | {
+ action?: 'post' | 'post_redirect';
+ label: string;
+ };
+
+type FrameImageMetadata = {
+ src: string;
+ aspectRatio?: '1.91:1' | '1:1';
+};
+
+type FrameInputMetadata = {
+ text: string;
+};
+
+type FrameMetadataType = {
+ // A list of strings which are the label for the buttons in the frame (max 4 buttons).
+ buttons?: [FrameButtonMetadata, ...FrameButtonMetadata[]];
+ // An image which must be smaller than 10MB and should have an aspect ratio of 1.91:1
+ image: FrameImageMetadata;
+ // The text input to use for the Frame.
+ input?: FrameInputMetadata;
+ // A valid POST URL to send the Signature Packet to.
+ postUrl?: string;
+ // A period in seconds at which the app should expect the image to update.
+ refreshPeriod?: number;
+};
+```
diff --git a/site/docs/pages/framekit/introduction.mdx b/site/docs/pages/framekit/introduction.mdx
index 6370383d4a..34c6bfea85 100644
--- a/site/docs/pages/framekit/introduction.mdx
+++ b/site/docs/pages/framekit/introduction.mdx
@@ -2,361 +2,15 @@
A Frame transforms any cast into an interactive app.
-Creating a frame is easy: select an image and add clickable buttons. When a button is clicked, you receive a callback and can send another image with more buttons. To learn more, check out "[Farcaster Frames Official Documentation](https://docs.farcaster.xyz/learn/what-is-farcaster/frames)".
-
-**React component**:
-
-- ``: This component renders all the Frame metadata elements in one place.
-
-**Typescript utilities**:
-
-- [`getFrameHtmlResponse()`](https://github.com/coinbase/onchainkit?tab=readme-ov-file#getframehtmlresponseframemetadata): Retrieves the **Frame HTML** for your HTTP responses.
-- [`getFrameMessage()`](https://github.com/coinbase/onchainkit?tab=readme-ov-file#getframemessageframerequest): Retrieves a valid **Frame message** from the Frame Signature Packet.
-- [`getFrameMetadata()`](https://github.com/coinbase/onchainkit?tab=readme-ov-file#getframeframemetadata): Retrieves valid **Frame metadata** for your initial HTML page with Next.js App Routing.
-
-
-
-### ``
-
-This component is utilized for incorporating Frame metadata elements into the React page.
-
-Note: If you are using Next.js with App routing, it is recommended to use `getFrameMetadata` instead.
-
-```tsx
-export default function HomePage() {
- return (
- ...
-
- ...
- );
-}
-```
-
-**@Props**
-
-```ts
-type FrameButtonMetadata =
- | {
- action: 'link' | 'mint';
- label: string;
- target: string;
- }
- | {
- action?: 'post' | 'post_redirect';
- label: string;
- };
-
-type FrameImageMetadata = {
- src: string;
- aspectRatio?: '1.91:1' | '1:1';
-};
-
-type FrameInputMetadata = {
- text: string;
-};
-
-type FrameMetadataType = {
- // A list of strings which are the label for the buttons in the frame (max 4 buttons).
- buttons?: [FrameButtonMetadata, ...FrameButtonMetadata[]];
- // An image which must be smaller than 10MB and should have an aspect ratio of 1.91:1 or 1:1
- image: FrameImageMetadata;
- // The text input to use for the Frame.
- input?: FrameInputMetadata;
- // A valid POST URL to send the Signature Packet to.
- postUrl?: string;
- // A period in seconds at which the app should expect the image to update.
- refreshPeriod?: number;
-};
-
-type FrameMetadataReact = FrameMetadataType & {
- wrapper?: React.ComponentType;
-};
-```
-
-**@Returns**
-
-```html
-
-
-
-
-
-
-
-
-
-
-
-```
-
-
-
-### getFrameHtmlResponse(frameMetadata)
-
-When you need to send an HTML Frame Response, the `getFrameHtmlResponse` method is here to assist you.
-
-It generates a valid HTML string response with a frame and utilizes `FrameMetadata` types for page metadata. This eliminates the need to manually create server-side HTML strings.
-
-```ts
-// Step 1. import getFrameHtmlResponse from @coinbase/onchainkit
-import { getFrameHtmlResponse } from '@coinbase/onchainkit';
-import { NextRequest, NextResponse } from 'next/server';
-
-async function getResponse(req: NextRequest): Promise {
- // Step 2. Build your Frame logic
- ...
-
- return new NextResponse(
- // Step 3. Use getFrameHtmlResponse to create a Frame response
- getFrameHtmlResponse({
- buttons: [
- {
- label: `We love BOAT`,
- },
- ],
- image: 'https://build-onchain-apps.vercel.app/release/v-0-17.png',
- postUrl: 'https://build-onchain-apps.vercel.app/api/frame',
- }),
- );
-}
-
-export async function POST(req: NextRequest): Promise {
- return getResponse(req);
-}
-```
-
-**@Param**
-
-```ts
-type FrameButtonMetadata =
- | {
- action: 'link' | 'mint';
- label: string;
- target: string;
- }
- | {
- action?: 'post' | 'post_redirect';
- label: string;
- };
-
-type FrameImageMetadata = {
- src: string;
- aspectRatio?: '1.91:1' | '1:1';
-};
-
-type FrameInputMetadata = {
- text: string;
-};
-
-type FrameMetadataType = {
- // A list of strings which are the label for the buttons in the frame (max 4 buttons).
- buttons?: [FrameButtonMetadata, ...FrameButtonMetadata[]];
- // An image which must be smaller than 10MB and should have an aspect ratio of 1.91:1 or 1:1
- image: FrameImageMetadata;
- // The text input to use for the Frame.
- input?: FrameInputMetadata;
- // A valid POST URL to send the Signature Packet to.
- postUrl?: string;
- // A period in seconds at which the app should expect the image to update.
- refreshPeriod?: number;
-};
-```
-
-**@Returns**
-
-```ts
-type FrameHTMLResponse = string;
-```
-
-
-
-### getFrameMessage(frameRequest)
-
-When a user interacts with your Frame, you receive a JSON message called the "Frame Signature Packet". Decode and validate this message using the `getFrameMessage` function.
-
-You can also use `getFrameMessage` to access useful information such as:
-
-- button: number
-- fid: number
-- following: boolean
-- liked: boolean
-- recasted: boolean
-- verified_accounts: string[]
-
-Note that if the `message` is not valid, it will be undefined.
-
-```ts
-// Step 1. import getFrameMessage from @coinbase/onchainkit
-import { FrameRequest, getFrameMessage } from '@coinbase/onchainkit';
-import { NextRequest, NextResponse } from 'next/server';
-
-async function getResponse(req: NextRequest): Promise {
- // Step 2. Read the body from the Next Request
- const body: FrameRequest = await req.json();
- // Step 3. Validate the message
- const { isValid, message } = await getFrameMessage(body , {
- neynarApiKey: 'NEYNAR_ONCHAIN_KIT'
- });
-
- // Step 4. Determine the experience based on the validity of the message
- if (isValid) {
- // the message is valid
- } else {
- // sorry, the message is not valid and it will be undefined
- }
-
- ...
-}
-
-export async function POST(req: NextRequest): Promise {
- return getResponse(req);
-}
-```
-
-**@Param**
-
-```ts
-// The Frame Signature Packet body
-type FrameMessage = {
- body: FrameRequest;
- messageOptions?: FrameMessageOptions;
-};
-
-type FrameMessageOptions =
- | {
- // The API key to use for validation. Default: NEYNAR_ONCHAIN_KIT
- neynarApiKey?: string;
- // Whether to cast the reaction context. Default: true
- castReactionContext?: boolean;
- // Whether to follow the context. Default: true
- followContext?: boolean;
- }
- | undefined;
-```
-
-**@Returns**
-
-```ts
-type Promise;
-
-type FrameValidationResponse =
- | { isValid: true; message: FrameValidationData }
- | { isValid: false; message: undefined };
-
-interface FrameValidationData {
- button: number; // Number of the button clicked
- following: boolean; // Indicates if the viewer clicking the frame follows the cast author
- input: string; // Text input from the viewer typing in the frame
- interactor: {
- fid: number; // Viewer Farcaster ID
- custody_address: string; // Viewer custody address
- verified_accounts: string[]; // Viewer account addresses
- };
- liked: boolean; // Indicates if the viewer clicking the frame liked the cast
- raw: NeynarFrameValidationInternalModel;
- recasted: boolean; // Indicates if the viewer clicking the frame recasted the cast
- valid: boolean; // Indicates if the frame is valid
-}
-```
-
-
-
-### getFrameMetadata(frameMetadata)
-
-With Next.js App routing, use the `getFrameMetadata()` inside your `page.ts` to get the metadata need it for your Frame.
-
-```ts
-// Step 1. import getFrameMetadata from @coinbase/onchainkit
-import { getFrameMetadata } from '@coinbase/onchainkit';
-import type { Metadata } from 'next';
-import HomePage from './home';
-
-// Step 2. Use getFrameMetadata to shape your Frame metadata
-const frameMetadata = getFrameMetadata({
- buttons: [
- {
- label: 'We love BOAT',
- },
- ],
- image: 'https://build-onchain-apps.vercel.app/release/v-0-17.png',
- postUrl: 'https://build-onchain-apps.vercel.app/api/frame',
-});
-
-// Step 3. Add your metadata in the Next.js metadata utility
-export const metadata: Metadata = {
- manifest: '/manifest.json',
- other: {
- ...frameMetadata
- },
-};
-
-export default function Page() {
- return ;
-}
-```
-
-**@Param**
-
-```ts
-type FrameButtonMetadata =
- | {
- action: 'link' | 'mint';
- label: string;
- target: string;
- }
- | {
- action?: 'post' | 'post_redirect';
- label: string;
- };
-
-type FrameImageMetadata = {
- src: string;
- aspectRatio?: '1.91:1' | '1:1';
-};
-
-type FrameInputMetadata = {
- text: string;
-};
-
-type FrameMetadataType = {
- // A list of strings which are the label for the buttons in the frame (max 4 buttons).
- buttons?: [FrameButtonMetadata, ...FrameButtonMetadata[]];
- // An image which must be smaller than 10MB and should have an aspect ratio of 1.91:1
- image: FrameImageMetadata;
- // The text input to use for the Frame.
- input?: FrameInputMetadata;
- // A valid POST URL to send the Signature Packet to.
- postUrl?: string;
- // A period in seconds at which the app should expect the image to update.
- refreshPeriod?: number;
-};
-```
-
-**@Returns**
-
-```ts
-type FrameMetadataResponse = Record;
-```
+Creating a frame is easy: select an image and add clickable buttons. When a button is clicked,
+you receive a callback and can send another image with more buttons.
+To learn more, check out "[Farcaster Frames Official Documentation](https://docs.farcaster.xyz/learn/what-is-farcaster/frames)".
+
+To assist you in engaging with Frames, here is the Frame Kit which includes:
+
+- Components:
+ - [``](/framekit/frame-metadata)
+- Utilities:
+ - [`getFrameHtmlResponse`](/framekit/get-frame-html-response)
+ - [`getFrameMessage`](/framekit/get-frame-message)
+ - [`getFrameMetadata`](/framekit/get-frame-metadata)
diff --git a/site/docs/pages/framekit/types.mdx b/site/docs/pages/framekit/types.mdx
new file mode 100644
index 0000000000..4de990f2b1
--- /dev/null
+++ b/site/docs/pages/framekit/types.mdx
@@ -0,0 +1 @@
+# Types [Glossary of Types in Frame Kit.]
diff --git a/site/docs/pages/identitykit/types.mdx b/site/docs/pages/identitykit/types.mdx
new file mode 100644
index 0000000000..2652ed5879
--- /dev/null
+++ b/site/docs/pages/identitykit/types.mdx
@@ -0,0 +1 @@
+# Types [Glossary of Types in Identity Kit.]
diff --git a/site/sidebar.ts b/site/sidebar.ts
index ea11b856cf..d61becdeb2 100644
--- a/site/sidebar.ts
+++ b/site/sidebar.ts
@@ -29,10 +29,48 @@ export const sidebar = [
},
{
text: 'Frame Kit',
- items: [{ text: 'Introduction', link: '/framekit/introduction' }],
+ items: [
+ { text: 'Introduction', link: '/framekit/introduction' },
+ {
+ text: 'Components',
+ items: [
+ {
+ text: 'FrameMetadata',
+ link: '/framekit/frame-metadata',
+ },
+ ],
+ },
+ {
+ text: 'Utilities',
+ items: [
+ {
+ text: 'getFrameHtmlResponse',
+ link: '/framekit/get-frame-html-response',
+ },
+ {
+ text: 'getFrameMessage',
+ link: '/framekit/get-frame-message',
+ },
+ {
+ text: 'getFrameMetadata',
+ link: '/framekit/get-frame-metadata',
+ },
+ ],
+ },
+ {
+ text: 'Types',
+ link: '/framekit/types',
+ },
+ ],
},
{
text: 'Identity Kit',
- items: [{ text: 'Introduction', link: '/identitykit/introduction' }],
+ items: [
+ { text: 'Introduction', link: '/identitykit/introduction' },
+ {
+ text: 'Types',
+ link: '/identitykit/types',
+ },
+ ],
},
] as const satisfies Sidebar;
diff --git a/src/core/getFrameMetadata.test.ts b/src/core/getFrameMetadata.test.ts
index ffba48b76c..832dddadbe 100644
--- a/src/core/getFrameMetadata.test.ts
+++ b/src/core/getFrameMetadata.test.ts
@@ -166,4 +166,25 @@ describe('getFrameMetadata', () => {
'fc:frame:post_url': 'post_url',
});
});
+
+ it('should render the target metadata for post and post_redirect when used', () => {
+ expect(
+ getFrameMetadata({
+ buttons: [
+ { label: 'button1', action: 'post', target: 'https://zizzamia.xyz/api/frame1' },
+ { label: 'button2', action: 'post_redirect', target: 'https://zizzamia.xyz/api/frame2' },
+ ],
+ image: 'image',
+ }),
+ ).toEqual({
+ 'fc:frame': 'vNext',
+ 'fc:frame:button:1': 'button1',
+ 'fc:frame:button:1:action': 'post',
+ 'fc:frame:button:1:target': 'https://zizzamia.xyz/api/frame1',
+ 'fc:frame:button:2': 'button2',
+ 'fc:frame:button:2:action': 'post_redirect',
+ 'fc:frame:button:2:target': 'https://zizzamia.xyz/api/frame2',
+ 'fc:frame:image': 'image',
+ });
+ });
});