A comprehensive Farcaster MiniApp showcasing the complete MiniKit and OnchainKit integration. This one-shot tutorial demonstrates building a fully functional social trivia game with wallet connection, onchain score saving, and Farcaster social features - all in one complete example.
- Complete MiniKit Integration: Full implementation of Farcaster Frames with account association
- OnchainKit Wallet Connection: Seamless Base Account (Smart Wallet) support
- Gas-Sponsored Transactions: Save scores onchain with zero gas fees via Paymaster
- Interactive Trivia Game: Web3-themed questions testing blockchain knowledge
- Compose Cast Integration: Share your trivia results with friends on Farcaster
- Background Notifications: Redis-backed notification system with webhooks
- Profile Viewing: Integrated Farcaster profile viewing from leaderboard
- Onchain Leaderboard: Smart contract for storing and retrieving scores
- Modern Mobile UI: Responsive design optimized for mobile frame experience
- 5 Questions Per Game: Curated Web3 and blockchain-themed questions
- Multiple Choice Answers: Four options per question
- Real-time Scoring: 20 points per correct answer (100 points max)
- Skip Functionality: Use primary button to skip difficult questions
- Progress Tracking: Visual indication of question progress
- Leaderboard: View top scorers with profile pictures and usernames
- Share Results: Compose cast to share your score with the Farcaster community
- Profile Integration: Click leaderboard entries to view Farcaster profiles
- User Context: Display connected user's profile picture and display name
- MiniKit: Farcaster's mini app framework for embedded experiences
- OnchainKit: Coinbase's React components and utilities for onchain apps
- Next.js 15: Modern React framework with App Router
- Farcaster Frame SDK: Native frame integration and hooks
- Redis (Upstash): Optional background notifications support
- Wagmi: React hooks for Ethereum interactions
- Viem: TypeScript interface for Ethereum
- Tailwind CSS: Utility-first CSS framework
- Base Sepolia: Testnet blockchain for safe testing
- Node.js (v18 or later)
- npm, yarn, pnpm, or bun package manager
- Farcaster account for testing the mini app
- OnchainKit API key from Coinbase Developer Platform
- (Optional) Redis instance from Upstash for notifications
- (Optional) Base Sepolia testnet ETH for testing
# Clone the repository
git clone https://github.com/HeimLabs/coinbase-cdp-demos.git
cd 19-One-Shot-Full-Miniapp-Tutorial
# Install dependencies
npm install
# or
yarn install
# or
pnpm install
# or
bun installCreate a .env.local file in the root directory:
# Copy the example environment file
cp env.example .env.localConfigure the required environment variables:
# Required: OnchainKit Configuration
NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME=Social Trivia
NEXT_PUBLIC_URL=http://localhost:3000
NEXT_PUBLIC_ICON_URL=http://localhost:3000/icon.png
NEXT_PUBLIC_ONCHAINKIT_API_KEY=your_onchainkit_api_key_here
# Frame Metadata (generate with: npx create-onchain --manifest)
FARCASTER_HEADER=
FARCASTER_PAYLOAD=
FARCASTER_SIGNATURE=
NEXT_PUBLIC_APP_ICON=http://localhost:3000/icon.png
NEXT_PUBLIC_APP_SUBTITLE=Test your Web3 knowledge
NEXT_PUBLIC_APP_DESCRIPTION=Play trivia and save your score onchain
NEXT_PUBLIC_APP_SPLASH_IMAGE=http://localhost:3000/splash.png
NEXT_PUBLIC_SPLASH_BACKGROUND_COLOR=#1a1a1a
NEXT_PUBLIC_APP_PRIMARY_CATEGORY=game
NEXT_PUBLIC_APP_HERO_IMAGE=http://localhost:3000/hero.png
NEXT_PUBLIC_APP_TAGLINE=Social Trivia - Test Your Web3 Knowledge
NEXT_PUBLIC_APP_OG_TITLE=Social Trivia
NEXT_PUBLIC_APP_OG_DESCRIPTION=Play trivia and save your score onchain
NEXT_PUBLIC_APP_OG_IMAGE=http://localhost:3000/hero.png
# Optional: Paymaster (enables gas-sponsored transactions)
NEXT_PUBLIC_PAYMASTER_URL=
# Optional: Redis (enables background notifications)
REDIS_URL=
REDIS_TOKEN=- Visit Coinbase Developer Platform
- Sign in or create an account
- Create a new project
- Copy your API key and add it to
.env.local
To enable Farcaster account association and notifications:
# Generate frame manifest with account association
npx create-onchain --manifestThis will update your environment variables with the proper Farcaster headers.
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun devOpen http://localhost:3000 to view the mini app.
- Launch the App: Open the mini app in Farcaster or your browser
- Connect Wallet (Optional): Connect your Base Account to save scores onchain
- Click "Start Game": Begin your trivia challenge
- Add to Favorites (Optional): Save the frame to your Farcaster account
- Read the Question: Each question has 4 multiple choice answers
- Select Your Answer: Tap on your chosen answer
- Progress Through: Answer all 5 questions to complete the game
- Skip if Needed: Use the "Skip Question" primary button for difficult questions
- View Your Score: See your final score out of 100 points
- Share Result: Use "Share Result" to cast your score to Farcaster
- Save Onchain: Click "Save Score Onchain" to permanently record your score (requires wallet connection)
- View Leaderboard: Check how you rank against other players
- Play Again: Start a new game with shuffled questions
The app leverages MiniKit's full capability stack:
// MiniKit Provider Setup
<OnchainKitProvider
miniKit={{ enabled: true }}
config={{
paymaster: process.env.NEXT_PUBLIC_PAYMASTER_URL,
}}
>
{children}
</OnchainKitProvider>- TriviaGame.tsx: Main game logic and state management
- QuestionScreen.tsx: Individual question display and answer handling
- ResultsScreen.tsx: Score display and onchain saving functionality
- Leaderboard.tsx: Display top scorers with profile integration
- AppLayout.tsx: Shared layout with mobile optimization
// Frame lifecycle management
const { setFrameReady, isFrameReady, context } = useMiniKit();
// Primary button configuration
usePrimaryButton({ text: 'Start Game' }, () => startNewGame());
// Social features
const { composeCast } = useComposeCast();
const viewProfile = useViewProfile();
const closeFrame = useClose();
const addFrame = useAddFrame();The app interacts with a Leaderboard contract on Base Sepolia:
Contract Address: 0x3f9F825af4d6B5058b4B06CE300325aD7449B835
// Saving score to the leaderboard
<Transaction
chainId={baseSepolia.id}
calls={[{
address: "0x3f9F825af4d6B5058b4B06CE300325aD7449B835",
abi: LEADERBOARD_ABI,
functionName: 'addScore',
args: [BigInt(score)],
}]}
isSponsored={true} // Gas-sponsored via Paymaster
>
<TransactionButton text="Save Score Onchain 🏆" />
</Transaction>Contract ABI:
function addScore(uint256 score) external;19-One-Shot-Full-Miniapp-Tutorial/
├── app/
│ ├── api/
│ │ ├── notify/route.ts # Notification endpoint
│ │ └── webhook/route.ts # Webhook handler for frame events
│ ├── components/
│ │ ├── AppLayout.tsx # Shared layout wrapper
│ │ ├── TriviaGame.tsx # Main game controller
│ │ ├── QuestionScreen.tsx # Question display
│ │ ├── ResultsScreen.tsx # Results & onchain saving
│ │ └── Leaderboard.tsx # Leaderboard display
│ ├── page.tsx # Entry point
│ ├── layout.tsx # Frame metadata & providers
│ ├── providers.tsx # OnchainKit configuration
│ ├── globals.css # Global styles
│ └── theme.css # OnchainKit theme customization
├── lib/
│ ├── trivia-data.ts # Question database
│ ├── notification.ts # Notification utilities
│ ├── notification-client.ts # Client-side notifications
│ └── redis.ts # Redis configuration
├── public/ # Frame assets (icons, images)
├── env.example # Environment template
└── package.json # Dependencies
Edit lib/trivia-data.ts:
const triviaQuestions: TriviaQuestion[] = [
{
id: '1',
question: "Your question here?",
answers: [
"Option A",
"Option B",
"Option C",
"Option D"
],
correctAnswer: 1, // Index of correct answer (0-3)
category: "Web3",
difficulty: "easy",
source: "https://example.com/source"
},
// Add more questions...
];Modify the scoring logic in TriviaGame.tsx:
const handleAnswer = (isCorrect: boolean) => {
if (isCorrect) {
setScore(score + 20); // Change points per question
}
// ...
};- Deploy a contract with an
addScore(uint256)function - Update the contract address in
ResultsScreen.tsx:
const CONTRACT_ADDRESS = "0xYourNewContractAddress";Update app/theme.css for custom colors and styles:
:root {
--ock-bg-default: #1a1a1a;
--ock-bg-alternate: #2a2a2a;
--ock-text-default: #ffffff;
--ock-accent: #3b82f6;
}- Push to GitHub: Commit your changes and push to GitHub
- Import to Vercel: Go to Vercel and import your repository
- Add Environment Variables: Copy all variables from
.env.localto Vercel - Update URLs: Change
NEXT_PUBLIC_URLto your Vercel URL - Deploy: Click deploy and wait for completion
- Get Your URL: Copy your deployed Vercel URL
- Create a Cast: Post a cast on Farcaster with your frame URL
- Test the Frame: Click the "Launch" button in your cast
- Share with Community: Let others play and share their scores
This tutorial demonstrates:
- Frame lifecycle management with
useMiniKit() - Primary button configuration with
usePrimaryButton() - Social features: compose cast, view profile, add frame
- Frame context and user data access
- Account association and webhooks
- Wallet connection with Base Account support
- Transaction components for onchain interactions
- Identity components (Avatar, Name)
- Gas sponsorship via Paymaster
- Transaction status monitoring
- Secure context usage (display only, not authorization)
- Error handling and loading states
- Mobile-first responsive design
- Environment variable management
- Smart contract integration patterns
npm run dev: Start development server on http://localhost:3000npm run build: Build for productionnpm run start: Start production servernpm run lint: Run ESLint for code quality
- Local Testing: Use the development server at http://localhost:3000
- ngrok Testing: Use ngrok for testing in Farcaster:
ngrok http 3000
- Frame Validator: Use Farcaster's frame validator tools
- Mobile Testing: Test on actual mobile devices within Farcaster client
- Check Console: Look for MiniKit initialization logs
- Verify Environment Variables: Ensure all required vars are set
- Test Wallet Connection: Try connecting with different wallet types
- Monitor Transactions: Use Base Sepolia block explorer
- Redis Optional: App works without Redis, just no notifications
- MiniKit Documentation
- OnchainKit Documentation
- Farcaster Frame SDK
- CDP Documentation
- Base Network Documentation
- Wagmi Documentation
- Viem Documentation
- Never commit sensitive data: Keep
.env.localin.gitignore - Use testnet first: Always test on Base Sepolia before mainnet
- Validate context: Never use unverified context for authorization
- Rate limiting: Implement for production API endpoints
- Monitor gas sponsorship: Set limits to prevent abuse
- HTTPS required: Use HTTPS for production deployments
- Webhook verification: Verify FID ownership in webhook handlers
Frame not loading?
- Check that all environment variables are set correctly
- Verify your OnchainKit API key is valid
- Ensure your URL is accessible (use ngrok for local testing)
Wallet won't connect?
- Try refreshing the frame
- Check that you're on the correct network (Base)
- Verify Paymaster URL is set (optional but recommended)
Transaction failing?
- Ensure you have Base Sepolia ETH (get from faucet)
- Check that the contract address is correct
- Verify the transaction parameters
Notifications not working?
- Notifications are optional and require Redis setup
- Check REDIS_URL and REDIS_TOKEN are set correctly
- Verify webhook is accessible from internet
Contributions are welcome! To contribute:
- Fork the repository
- Create a feature branch (
git checkout -b feature/new-questions) - Commit your changes (
git commit -m 'Add new trivia questions') - Push to the branch (
git push origin feature/new-questions) - Open a Pull Request
Disclaimer: This project is for educational and demonstration purposes. For production use, additional security measures, testing, and monitoring should be implemented. Always test thoroughly on testnets before deploying to mainnet.
Built with ❤️ using MiniKit and OnchainKit