Skip to content

Vercel Serverless

Quick Start

You can scaffold a Frog project with Vercel Serverless integrated via the create-frog CLI:

npm
npm init frog -- -t vercel

Manual Installation

Install Vercel

npm install vercel --save-dev

Build your Frame

Next, scaffold your frame:

api/index.tsx
import { Button, Frog } from 'frog'
 
// Uncomment to use Edge Runtime.
// export const config = {
//   runtime: 'edge',
// }
 
export const app = new Frog({ 
  basePath: '/api',
  title: 'Frog Frame',
})
 
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 Vercel Handlers

After that, we will append Vercel handlers to the file.

api/index.tsx
import { Button, Frog } from 'frog'
import { handle } from 'frog/next'
 
// Uncomment to use Edge Runtime.
// export const config = {
//   runtime: 'edge',
// }
 
export const app = new Frog({ 
  basePath: '/api',
  title: 'Frog Frame',
})
 
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.

api/index.tsx
import { Button, Frog } from 'frog'
import { handle } from 'frog/next'
import { devtools } from 'frog/dev'
import { serveStatic } from 'frog/serve-static'
 
export const app = new Frog({ 
  basePath: '/api',
  title: 'Frog Frame',
})
 
app.frame('/', (c) => {
  ...
})
 
Devtools should be called after all frames are defined.
if (import.meta.env?.MODE === 'development') devtools(app, { serveStatic })else devtools(app, { assetsPath: '/.frog' }) export const GET = handle(app) export const POST = handle(app)

Add Scripts to package.json

Then we will add a build & deploy script to deploy our Vercel Serverless function.

{
  "scripts": {
    "build": "frog vercel-build",
    "dev": "frog dev",
    "deploy": "vercel"
  },
  "dependencies": {
    "hono": "latest",
    "frog": "latest"
  },
  "devDependencies": {
    "vercel": "latest"
  }
}

Navigate to Frame

Then, we can navigate to our frame in the browser:

npm run dev

http://localhost:5173/api

Bonus: Deploy

When ready, we can deploy our application.

This example deploys to Vercel via the Vercel CLI (vercel).

npm run deploy

Bonus: Browser Redirects

If a user navigates to your frame in the browser, we may want to redirect them to another webpage that corresponds to the frame.

In the example below, when a user navigates to the /api/ path of the website via their web browser, they will be redirected to the / path.

Read more on Browser Redirects

api/index.tsx
import { Button, Frog } from 'frog'
import { handle } from 'frog/next' 
 
// Uncomment to use Edge Runtime.
// export const config = {
//   runtime: 'edge',
// }
 
export const app = new Frog({ 
  basePath: '/api',
  browserLocation: '/:path'
  title: 'Frog Frame',
})
 
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)