Skip to content

Overview

High-level overview of the Frog API

Frog is built on top of Hono (a fast & lightweight Web Framework), extended with a first-class API for Farcaster Frames.

If you are familiar with other Web Frameworks such as Express, Koa, or Fastify, then the Frog (and Hono) API should seem familiar to you.

At a high-level, the most basic Frog application looks like this:

src/index.tsx
import { Button, Frog } from 'frog'
 
export const app = new Frog()
 
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>
    ]
  })
})

Below, we will break down high-level concepts of the above example.

Imports

Before we can instantiate an application, we need to import the Frog class.

import { Button, Frog } from 'frog'
 
export const app = new Frog()
 
// ...

Instantiation

We instantiate a new Frog application by calling the Frog class.

import { Button, Frog } from 'frog'
 
export const app = new Frog()
 
app.frame('/', (c) => {
  const { buttonValue, status } = c
  // ...

You can pass optional constructor parameters to new Frog() to:

Routing

Similar to .post, .get, .put, etc in other Web Frameworks, Frog uses .frame to define a new frame route.

Internally, the frame route automatically handles GET and POST requests sent by Farcaster clients such as Warpcast to get frame metadata.

export const app = new Frog()
 
app.frame('/', (c) => {
  return c.res({/* ... */})
})

You can also define multiple routes by specifying alternative paths.

export const app = new Frog()
 
app.frame('/', (c) => {
  return c.res({/* ... */})
})
 
app.frame('/foo', (c) => {
  return c.res({/* ... */})
})
 
app.frame('/bar', (c) => {
  return c.res({/* ... */})
})

You can also define GET, POST, etc routes via the Hono instance.

export const app = new Frog()
 
app.frame('/', (c) => {
  return c.res({/* ... */})
})
 
app.hono.get('/healthcheck', (c) => {
  return c.text('ribbit')
})

This only scratches the surface of Routing in Frog. For more advanced routing, check out the Routing section.

Context

The c parameter in the frame route contains properties about the frame, such as:

export const app = new Frog()
 
app.frame('/', (c) => {
  const { buttonValue, inputText, status, verified } = c
  return c.res({/* ... */})
})

Read more on Context.

Images & Intents

Farcaster Frames have two main UI components: an Image, and a set of Intents:

Images & Intents

We can represent this in the Frog API via the image and intents properties of the frame route:

src/index.tsx
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>
    ]
  })
})

Read more on Images & Intents.

Dev Server & Devtools

To get a live preview of our frames, we can attach the Frog Devtools to our app.

src/index.tsx
import { devtools } from 'frog/dev'
import { serveStatic } from 'frog/serve-static'
 
export const app = new Frog()
 
app.frame('/', (c) => { ... })
 
devtools(app, { serveStatic })

Then, spin up a local dev server using the frog dev command:

frog dev

This will start a dev server at http://localhost:5173.

Then you can head to the /dev route (http://localhost:5173/dev) to see a live preview (with live reloading) of your frame.

Frog Devtools

Learn more about Frog's built-in devtools.