# Ship a Viral Base Mini App with MiniKit - from Scratch in Next.js > A hands-on walkthrough for social-native, onchain apps that launch inside the feed. **Published by:** [HeimLabs](https://paragraph.com/@heimlabs/) **Published on:** 2025-10-16 **URL:** https://paragraph.com/@heimlabs/ship-a-viral-base-mini-app-with-minikit-from-scratch-in-nextjs ## Content IntroductionApp installs, cold-start social graphs, and clunky wallets kill growth. Traditional apps fight for app-store rankings while your users bounce before the first tap. Today we’ll build a Base Mini App — a lightweight, social-native web app that launches instantly inside clients like the Base App and Farcaster. Using MiniKit (for frames + native hooks) and OnchainKit (for polished UI + onchain utilities), you’ll ship a “Social Trivia” app that feels at home in the feed and scales via sharing. By the end, you’ll have a working Mini App with a clean viral loop, context-aware UI, smooth native controls, and an optional gasless onchain leaderboard on Base.What You’ll Build⚡ Launch a Next.js Mini App with a signed Farcaster manifest🧭 Use MiniKit hooks for context, auth, share, and navigation🧑‍🤝‍🧑 Render identity with OnchainKit’s Avatar/Name components📣 Create a viral loop with dynamic embeds + useComposeCast⛽ Store scores onchain with a paymaster-sponsored flow (gasless UX)(Watch the Video here) System ArchitectureUser → Mini App (WebView in client): Tap-to-open from a cast or DM.MiniKit Context: Provides device safe areas, user FID, client info.UI & Logic (Next.js + OnchainKit): Trivia flow, identity display, sharing.Smart Contract (Base): Optional leaderboard storage, paymaster-sponsored.Social Client: Native share sheets, in-app browser, profile/cast deep links.MiniKit Harnesses the in-client runtime: safe area insets, native buttons, closing flows, social navigation, and sharing. OnchainKit UI primitives (Avatar, Name, …) and helpers that match ecosystem UX conventions. Blockchain (Base) Leaderboard contract on Base; optional paymaster for gasless writes.Part 1: The Why — Onchain Apps, Built for the FeedMini Apps flip the model. Instead of dragging users to an app store, the app goes to the user — living inside the feed, casting UI as content. You inherit an onchain social graph (Farcaster), skip installs, and unlock viral distribution.Part 2: The How — Build “Social Trivia” (End-to-End)PrerequisitesFarcaster account (for testing + manifest signing)Node.js v18+A tunneling service (e.g., ngrok) for public dev URLStep 1: Scaffold, Manifest & ValidationBootstrap the project# Scaffold a new Mini Appnpx create-onchain --miniCreate the Farcaster manifest at /public/.well-known/farcaster.json:function withValidProperties( properties: Record, ) { return Object.fromEntries( Object.entries(properties).filter(([key, value]) => { if (Array.isArray(value)) { return value.length > 0; } return !!value; }), ); } export async function GET() { const URL = process.env.NEXT_PUBLIC_URL; return Response.json({ accountAssociation: { header: process.env.FARCASTER_HEADER, payload: process.env.FARCASTER_PAYLOAD, signature: process.env.FARCASTER_SIGNATURE, }, frame: withValidProperties({ version: "1", name: process.env.NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME, subtitle: process.env.NEXT_PUBLIC_APP_SUBTITLE, description: process.env.NEXT_PUBLIC_APP_DESCRIPTION, screenshotUrls: [], iconUrl: process.env.NEXT_PUBLIC_APP_ICON, splashImageUrl: process.env.NEXT_PUBLIC_APP_SPLASH_IMAGE, splashBackgroundColor: process.env.NEXT_PUBLIC_SPLASH_BACKGROUND_COLOR, homeUrl: URL, webhookUrl: `${URL}/api/webhook`, primaryCategory: process.env.NEXT_PUBLIC_APP_PRIMARY_CATEGORY, tags: [], heroImageUrl: process.env.NEXT_PUBLIC_APP_HERO_IMAGE, tagline: process.env.NEXT_PUBLIC_APP_TAGLINE, ogTitle: process.env.NEXT_PUBLIC_APP_OG_TITLE, ogDescription: process.env.NEXT_PUBLIC_APP_OG_DESCRIPTION, ogImageUrl: process.env.NEXT_PUBLIC_APP_OG_IMAGE, }), baseBuilder: { allowedAddresses: ["base-builder-address-here"], }, }); }Dev tip: Farcaster clients can’t access localhost. Expose your app with ngrok and validate your URLs using the official Farcaster Manifest and Embed validators before debugging anything else.Step 2: Context-Aware UI with OnchainKit + MiniKitapp/components/AppLayout.tsx/// app/components/AppLayout.tsx 'use client'; import { useMiniKit } from '@coinbase/onchainkit/minikit'; import { ReactNode } from 'react'; export default function AppLayout({ children }: { children: ReactNode }) { const { context } = useMiniKit(); const style = { paddingTop: `${context?.client?.safeAreaInsets?.top ?? 0}px`, paddingBottom: `${context?.client?.safeAreaInsets?.bottom ?? 0}px`, minHeight: '100vh', display: 'flex', flexDirection: 'column' as const, }; return (
{children}
); }app/page.tsx// app/page.tsx // ⚠️ SECURITY CRITICAL: // The context object is for display and personalization ONLY. // It is unverified and must not be used to authorize actions on your backend. // For secure actions, you must use the useAuthenticate hook. // app/page.tsx "use client"; import { useEffect } from "react"; import { useMiniKit } from "@coinbase/onchainkit/minikit"; import AppLayout from "./components/AppLayout"; import TriviaGame from "./components/TriviaGame"; export default function App() { const { setFrameReady, isFrameReady, context } = useMiniKit(); const userFid = context?.user?.fid; const username = context?.user?.username; const pfpUrl = context?.user?.pfpUrl; const displayName = context?.user?.displayName; useEffect(() => { if (!isFrameReady) { setFrameReady(); } }, [setFrameReady, isFrameReady]); return (
{/* Header */}
{userFid ? ( <> {pfpUrl && ( {displayName )}

{displayName || username || 'Anonymous'}

) : (

Social Trivia

)}
{/* Game */}
); }Security note: context is not authentication. It’s for personalized display only. Use useAuthenticate for verified, server-authorized actions.Step 3: Engineer the Viral Social LoopA. Progressive Auth with useAuthenticate Let users play first. Only prompt auth when saving a score or calling your backend. B. Dynamic Embeds (Share Previews) Generate a share URL like /share?score=95&user=vitalik and render dynamic tags server-side so the cast preview becomes a personalized challenge card. C. Native Share with useComposeCast// app/components/ResultsScreen.tsx const { composeCast } = useComposeCast(); const handleShare = () => { const shareUrl = `https://your-trivia-app.xyz/share?score=${score}&user=${username}`; composeCast({ text: `I scored ${score}/100! Can you beat me?`, embeds: [shareUrl], }); };D. Deep Social Navigation// Leaderboard row → tap to view Farcaster profile const viewProfile = useViewProfile(playerFid); return ;E. The Linking Rule: useOpenUrl (never raw )const openUrl = useOpenUrl('https://en.wikipedia.org/wiki/Trivia'); return ;Step 4: Native UI & Flow ControlPrimary Action with usePrimaryButtonusePrimaryButton({ text: 'Submit Answer' }, () => { handleSubmitAnswer(); });Graceful Exit with useCloseconst closeFrame = useClose(); return ;Step 5: Go Onchain — Gasless Leaderboard (Optional)Solidity Contract (simplified tutorial version)// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; contract TriviaLeaderboard { mapping(address => uint256) public scores; function addScore(uint256 score) public { // NOTE: In production, verify a server signature before accepting scores. scores[msg.sender] = score; } }Production Security Tip Never trust client-submitted scores. Verify on a server first, then sign {userAddress, score} with your server key. Have the contract check that signature before addScore updates storage. Pair with a Paymaster (Coinbase Developer Platform) to sponsor gas so the UX feels Web2-smooth. Frontend flow Configure MiniKitProvider with your Paymaster URL. Use standard wagmi hooks (useWriteContract) to store scores; MiniKit handles gasless plumbing under the hood.Part 3: Ship It — Deployment, Verification & RegistrationStep 6: Deploy & Verify OwnershipDeploy to Vercel (or similar).Update the manifest URLs to your final prod domain.In Base Build (base.dev): import your app, connect the wallet tied to your Farcaster account, and follow the verification prompts.Merge the provided baseBuilder object into your manifest, for example:{ "frame": { "name": "Social Trivia", "homeUrl": "https://your-final-app-url.xyz", "noindex": false }, "baseBuilder": { "allowedAddresses": [ "0x...your...verified...address" ] } }Redeploy with this final manifest, then submit your production URL on Base Build to complete verification.Step 7: Official Registration & AnalyticsRegistering your app unlocks:Directory discovery in the Base AppAnalytics for installs, usage, and retentionConclusion & Call to ActionRecapYou built a social-native Mini App with MiniKit + OnchainKit: context-aware UI, native controls, viral sharing, deep social navigation, and an optional gasless onchain leaderboard on Base.Next StepsTweak copy and visuals on your dynamic share previews.Add useAddFrame (save to favorites) and useNotification (re-engagement) as they roll out.Harden your onchain writes with server-verified signatures and a paymaster.CTAExplore Base Docs to go deeper on Mini Apps.Ship your v1, share it in the Base community, and tag @HeimLabs with what you build!Resources & LinksBase Docs (Mini Apps):Base - Base DocumentationThe #1 Ethereum Layer 2, incubated by Coinbasehttps://docs.base.orgOnchainKit Documentation: Base | OnchainKitBase is a secure, low-cost, builder-friendly Ethereum L2 built to bring the next billion users onchain.https://www.base.orgFarcaster Docs:Farcaster DocsA protocol for building sufficiently decentralized social networks.https://docs.farcaster.xyzBase Discord: Join the Base Discord Server!Base is a secure, low-cost, developer-friendly Ethereum L2 built to bring the next billion users onchain | 476227 membershttps://discord.comDemo Codebase:GitHub - HeimLabs/coinbase-cdp-demos: A collection of Demo Projects exploring the Coinbase Developer PlatformA collection of Demo Projects exploring the Coinbase Developer Platform - HeimLabs/coinbase-cdp-demoshttps://github.comHeimLabs:HeimLabs | Trusted Blockchain Solutions ProviderRevolutionize your business with HeimLabs' blockchain development solutions. Our expert team offers end-to-end services for smart contracts, DApps & more.https://www.heimlabs.comClap if this saved you hours, and share what you’re building with the CDP stack! Follow HeimLabs for unapologetically practical Web3 dev content. Twitter, LinkedIn. Happy Building 🚀 ## Publication Information - [HeimLabs](https://paragraph.com/@heimlabs/): Publication homepage - [All Posts](https://paragraph.com/@heimlabs/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@heimlabs): Subscribe to updates - [Twitter](https://twitter.com/heimlabs): Follow on Twitter - [Farcaster](https://farcaster.xyz/heimlabs): Follow on Farcaster