Skip to content

Frequently Asked Questions (FAQ)

Frequently asked questions related to Frog.

Feel free to add to this document if you notice frequently asked questions that are not covered here.

Why is my frame handler being invoked twice?

In Frog, there are two render cycles for .frame handlers: one for the "main" frame endpoint, and "OG image" frame endpoint.

If we want to enforce idempotency, we can distinguish between the two cycles by using the cycle property on context:

import { Button, Frog } from 'frog'
import { db } from './db'
 
export const app = new Frog()
 
app.frame('/', (c) => {
  const { buttonValue, cycle } = c
 
  if (cycle === 'main') db.save(buttonValue)
 
  return c.res({
    image: (
      <div style={{ color: 'white', display: 'flex', fontSize: 60 }}>
        Selected: {buttonValue}
      </div>
    ),
    intents: [
      <Button value="apple">Apple</Button>,
      <Button value="banana">Banana</Button>,
      <Button value="mango">Mango</Button>
    ]
  })
})

It is worth noting that the deriveState function is idempotent by default, and it is only invoked once.

import { Button, Frog } from 'frog'
import { db } from './db'
 
export const app = new Frog({
  initialState: {
    count: 0,
    number: 0
  }
})
 
app.frame('/', (c) => {
  const { buttonValue, cycle, deriveState } = c
 
  const state = deriveState((previousState) => {
    previousState.number = Math.random()
    previousState.count++
  })
`state.number` will be equal between render cycles:
(cycle = "main") `state.number`: 0.270822354849678, `state.count`: 1
(cycle = "image") `state.number`: 0.270822354849678, `state.count`: 1