celo-personality: The Quiz That Hides a Cross-Chain Identity Stack

A Farcaster Mini App that turns onboarding into a personality test, then verifies identity across Farcaster, Optimism, and Celo behind the scenes.

11 min read • View on GitHub • More from sodofi

A playful quiz booth sits on top of a much more serious machine, with hidden gears, keys, and chain links running underneath the counter. The scene explains that the user experience is light and social while the real work is identity verification and session handling.
The front end feels like a quiz. The back end behaves like onboarding infrastructure.
Key Takeaways

A quiz that is really onboarding

On the surface, celo-personality asks playful questions and returns a Celo-flavored archetype. Under the hood, it is doing something more strategic. It treats the quiz as a cover story for identity resolution, session minting, and future re-engagement.

That matters because most crypto onboarding still starts with the hardest step first. This repo does the opposite. It gives the user something lightweight to do, then uses the result to move them through auth and into the app.

Why this belongs inside Farcaster

Farcaster is not just distribution here. It is the container that makes the whole trick believable. The app can initialize inside the client, call sdk.actions.ready(), and meet users where social identity already exists.

That is a better fit than a standalone landing page because the user is already authenticated as a person, not just a wallet. The mini-app wrapper and quick-auth flow turn social context into the first trusted signal.

A small arcade cabinet is embedded inside a larger phone screen, with a cheerful interface on top and guarded circuitry underneath. The image explains how the app lives inside Farcaster while hiding a more serious trust stack below the surface.
The container is social. The machinery is not.

The identity sandwich

The technical surprise is that identity is verified in layers. The app receives a Farcaster token, checks it with quick-auth, binds it to the user's FID, and then uses chain data to make sure the same person is still the same person.

The key registry check on Optimism is the part that usually gets missed. Farcaster's trust lives on one chain. The app lives on another. This repo connects them without asking the user to think about the boundary.

The app only looks like a quiz. The actual flow is social auth, chain verification, then personalized follow-through.

// Simplified from apps/web/src/app/api/auth/sign-in/route.ts
import { quickAuthClient } from "@farcaster/quick-auth";
import { SignJWT } from "jose";

export async function POST(req: Request) {
  const { token } = await req.json();

  const verified = await quickAuthClient.verifyJwt({
    token,
    domain: process.env.DOMAIN!,
  });

  const session = await new SignJWT({
    fid: verified.fid,
    address: verified.custodyAddress,
  })
    .setProtectedHeader({ alg: "HS256" })
    .setIssuedAt()
    .setExpirationTime("7d")
    .sign(new TextEncoder().encode(process.env.JWT_SECRET));

  return Response.json({ session });
}

The important detail is not the JWT syntax. It is the boundary. Farcaster verifies identity, the app issues a local session, and the rest of the mini app can stay light enough to move fast.

The quiz engine keeps the app from feeling like a login form

The quiz itself is state-driven React. It stores the questions as data, maps answers into a small personality model, and calculates the result by counting which archetype appears most often.

That sounds simple because it is supposed to sound simple. The point is to make the value obvious before the machinery shows up. A user gets a result card, a Celo flavor, and a reason to keep going.

Notifications are the hidden second act

The webhook and notification client are what turn a demo into a retention loop. Once the app stores a notification token, it can re-engage users without asking for an email address or phone number.

That is a small implementation choice with a large product effect. The quiz is not the end state. It is a trigger for future messages, future visits, and future identity-aware nudges.

The repo also pays attention to idempotency and ownership checks, which is exactly where toy mini apps usually get sloppy. Here, the aftercare is part of the architecture.

What it replaces

Typical crypto onboardingcelo-personality
Connect wallet first, then try to explain the app.Answer a quiz first, then let identity and session work happen in the background.
Identity is usually reduced to a wallet address.Identity starts with Farcaster context, then is checked again on-chain.
Retention often gets bolted on later.Notifications are part of the flow from the start.
The user feels like they are entering a form.The user feels like they are entering a social mini app.

That is why the project matters even as a prototype. It is not trying to make quizzes more entertaining. It is trying to make trust cheaper.