Next.js
Next.js is a React framework for building full-stack web applications.
Quick Start
You can scaffold a Frog project with Next.js integrated via the create-frog CLI:
npm init frog -- -t nextManual Installation
Install Next.js
npm install next@latest react@latest react-dom@latest vercel@latestBuild your Frame
Next, scaffold your frame:
/** @jsxImportSource frog/jsx */
import { Button, Frog, TextInput } from 'frog'
 
const app = new Frog({ 
  basePath: '/api',
})
 
app.frame('/', (c) => {
  const { buttonValue, status } = c
  return c.res({
    image: (
      <div style={{ color: 'white', display: 'flex', fontSize: 60 }}>
        {status === 'initial' ? (
          'Select your fruit!'
        ) : (
          `Selected: ${buttonValue}`
        )}
      </div>
    ),
    intents: [
      <Button value="apple">Apple</Button>,
      <Button value="banana">Banana</Button>,
      <Button value="mango">Mango</Button>
    ]
  })
})Add Handlers
After that, we will add handlers to handle requests in the api/ route:
/** @jsxImportSource frog/jsx */
import { Button, Frog, TextInput } from 'frog'
import { handle } from 'frog/next'
 
const app = new Frog({ 
  basePath: '/api',
})
 
// Uncomment to use Edge Runtime
// export const runtime = 'edge'
 
app.frame('/', (c) => {
  const { buttonValue, status } = c
  return c.res({
    image: (
      <div style={{ color: 'white', display: 'flex', fontSize: 60 }}>
        {status === 'initial' ? (
          'Select your fruit!'
        ) : (
          `Selected: ${buttonValue}`
        )}
      </div>
    ),
    intents: [
      <Button value="apple">Apple</Button>,
      <Button value="banana">Banana</Button>,
      <Button value="mango">Mango</Button>
    ]
  })
})
 
export const GET = handle(app)
export const POST = handle(app)Setup Devtools
Add Frog Devtools after all frames are defined. This way the devtools can automatically discover all your frames.
import { Button, Frog } from 'frog'
import { handle } from 'frog/next'
import { devtools } from 'frog/dev'
import { serveStatic } from 'frog/serve-static'
 
const app = new Frog({ 
  basePath: '/api',
})
 
app.frame('/', (c) => {
  ...
})
 
devtools(app, { serveStatic })
^ Devtools should be called after all frames are defined. export const GET = handle(app)
export const POST = handle(app)Add Scripts to package.json
Then we will add a Wrangler scripts to our package.json:
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "deploy": "vercel",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "hono": "latest",
    "frog": "latest",
    "next": "latest",
    "react": "latest",
    "react-dom": "latest",
    "vercel": "latest",
  },
}
 Navigate to Frame
Then, we can navigate to our frame in the browser:
npm run dev
http://localhost:3000/api
Bonus: Deploy
When ready, we can deploy our application.
This example deploys to Vercel via the Vercel CLI (vercel), but you can use any platform that supports Next.js
npm run deployBonus: Add Browser Redirects
If a user navigates to your frame in the browser, we may want to redirect them to the correct Next.js page route that corresponds to the frame.
In the example below, when a user navigates to the /api/foo path of the website via their web browser,
they will be redirected to the /foo path (ie. /app/foo/page.tsx in your Next.js App).
Read more on Browser Redirects
/** @jsxImportSource frog/jsx */
import { Button, Frog, TextInput } from 'frog'
import { handle } from 'frog/next'
 
const app = new Frog({ 
  basePath: '/api',
  browserLocation: '/:path',
})
 
// Uncomment to use Edge Runtime
// export const runtime = 'edge'
 
app.frame('/foo', (c) => {
  const { buttonValue, status } = c
  return c.res({
    image: (
      <div style={{ color: 'white', display: 'flex', fontSize: 60 }}>
        {status === 'initial' ? (
          'Select your fruit!'
        ) : (
          `Selected: ${buttonValue}`
        )}
      </div>
    ),
    intents: [
      <Button value="apple">Apple</Button>,
      <Button value="banana">Banana</Button>,
      <Button value="mango">Mango</Button>
    ]
  })
})
 
export const GET = handle(app) 
export const POST = handle(app) Bonus: Page & Frame Co-location
If a user shares a link to your website, we may want to render the frame in the page route itself, instead of forcing them to share a link to the Frog API route.
In the example below, when a user shares the / (= /page.tsx in your Next.js App)
path of the website on Warpcast, they will be able to see the frame.
This leverages the generateMetadata function built-in to Next.js
import { getFrameMetadata } from 'frog/next'
import type { Metadata } from 'next'
 
export async function generateMetadata(): Promise<Metadata> {
  const url = process.env.VERCEL_URL || 'http://localhost:3000'
  const frameMetadata = await getFrameMetadata(`${url}/api`)
  return {
    other: frameMetadata,
  }
}