celo-donation: The Farcaster Mini App That Turns a Donation Button Into a Full Stack
A Next.js starter that wires discovery, payments, uploads, and identity into one onchain social app, with the hard parts hidden in the plumbing.
- The repo treats Farcaster launchability as product infrastructure, because discovery metadata and `sdk.actions.ready()` decide whether the app ever feels native.
- The donation experience stays intentionally narrow so the template can hide the hard parts behind a clean state machine.
- FID-linked analytics turns a payment demo into a measurable growth surface, which is why the template is more useful than a one-off tutorial.
- Celo is the payment rail, but Farcaster is the operating context that gives the starter its real shape.
The donation button is the bait, not the story
The first trick in celo-donation is that the donation button is almost beside the point. The repo reads like a tiny fundraising app, but it behaves like a complete Farcaster Mini App template, with discovery metadata, SDK readiness, payment rails, uploads, and analytics all wired together. The visible UI is the least interesting layer.
That matters because mini apps fail in the seams. If the manifest is wrong, the app is hard to discover. If the SDK handshake is late, the shell never feels native. If payments, uploads, and identity tracking live in separate mental buckets, the whole thing degrades into a browser tab with a wallet button.
The launch path is the real product
The repo's opening move is the right one: make the Farcaster client recognize the app before you worry about the donation form. The critical pieces live in src/app/.well-known/farcaster.json, the page metadata, and the use-miniapp-sdk.ts hook that calls sdk.actions.ready() as soon as the view is live. In other words, the app earns its seat inside Farcaster before it asks for money.
useEffect(() => {
let mounted = true;
async function boot() {
await sdk.actions.ready();
if (mounted) setReady(true);
}
boot();
const offAdded = sdk.events.on("miniAppAdded", () => setPinned(true));
const offNotifs = sdk.events.on("notificationsEnabled", () => setNotifications(true));
return () => {
mounted = false;
offAdded();
offNotifs();
};
}, []);
The repo even marks the metadata section as a danger zone, and that warning is deserved. Mini-app discovery can fail on a single malformed meta block, so the template treats launchability as a first-class feature, not a build step to check later.
Why the donation flow feels simple on purpose
Once the shell is live, the donation experience is almost austere. The template keeps the choice set tiny, usually preset amounts like 1, 2, 5, or 10 USDC, then hands the transfer to Daimo Pay. That constraint is the design decision. It avoids the usual crypto-dapp clutter of address fields, chain confusion, and modal sprawl.
The post-payment state matters just as much as the payment. A clean thank-you screen turns a successful transfer into a complete interaction, which is rare in web3 demos. The repo treats that as product work, not decoration.
const [status, setStatus] = useState<"idle" | "paying" | "thank-you">("idle");
async function donate(amount: number) {
setStatus("paying");
await pay(amount);
setStatus("thank-you");
}
Identity-aware analytics makes the template useful
The smartest non-payment choice is the analytics layer. In src/app/providers.tsx, the app looks for the Farcaster FID and aliases the session in PostHog, which lets a founder see repeat behavior without inventing a separate identity system. That is a small implementation detail with a big product effect: anonymous traffic stops being disposable.
The same pattern makes the template easier to extend. If you add uploads with Supabase, or another onchain action later, the event trail stays attached to the same social identity layer. That is what turns a demo into a surface you can iterate on.
What this template replaces
| Project type | What it teaches | What it leaves out | Identity model | Best use case |
|---|---|---|---|---|
| Generic Next.js web3 starter | How to scaffold a dapp | Mini-app discovery, Farcaster readiness, analytics, uploads | Wallet first | Starting from zero |
| Celo crowdfunding tutorial | How to build a simple crowdfunding flow on Celo | Farcaster behavior and social identity | Wallet first | Learning onchain transfers |
| Bare Farcaster mini-app integration | How to launch inside Farcaster | Payments, uploads, and product analytics | Farcaster aware but thin | Spec compliance |
| celo-donation | How to ship a Farcaster-native donation template | Deep domain logic for a single campaign | FID linked and session aware | Building reusable social onchain apps |
So the repo's value is not that it does one thing well. It gives you the default architecture for a Farcaster-native app that can discover, launch, transact, and remember users without splitting those concerns across different starters.
Why Celo still matters
Celo is the rail, not the thesis. It gives the template a practical payment target and a low-friction stablecoin story, but the broader idea is platform design: onchain social apps work better when the social client, the payment flow, and the analytics layer are designed together. That is why this repo feels less like a donation example and more like a blueprint.