How to Build a Farcaster Mini App from Zero to Launch

Written by FURI6 min read

How to Build a Farcaster Mini App from Zero to Launch
On this page

This article explains, in plain English, how to turn a normal web app into a Farcaster Mini App that opens inside Warpcast or the Base app. You will see exactly what to add, where to put it, and how to ship it. The tone is practical and human. Copy the snippets as needed.


What you will build#

You will create a small React app that opens inside the Mini App frame, shows a share card when you post its link, and exposes a public manifest so the platform can index your app.

  • The UI is sized for the web frame and still works on mobile.
  • The page contains a share card (embed) with a launch button.
  • The site serves /.well-known/farcaster.json as the manifest.
  • The app calls ready() so the splash screen disappears.

Prerequisites#

  • Node.js 22.11 or newer
  • npm, pnpm, or yarn
  • A Farcaster account (Warpcast) with Developer Mode enabled

Enable Developer Mode. Open https://farcaster.xyz/~/settings/developer-tools and toggle Developer Mode to ON.


Step 1: Create the project#

You can use any framework. The example below uses React with Vite and TypeScript.

text
1npm create vite@latest my-miniapp -- --template react-ts
2cd my-miniapp
3npm i @farcaster/miniapp-sdk
4npm run dev

Open the local URL printed in your terminal. Keep the dev server running while you add the next steps.


Step 2: Add the share card (embed)#

Add the meta tag below to index.html inside the <head>. Replace the URLs and text with your own.

text
1<meta
2  name="fc:miniapp"
3  content='{
4    "version": "1",
5    "imageUrl": "https://YOUR-DOMAIN.com/og-3x2.png",
6    "button": {
7      "title": "Open App",
8      "action": {
9        "type": "launch_frame",
10        "name": "Your App Name",
11        "url": "https://YOUR-DOMAIN.com"
12      }
13    }
14  }'
15/>

Notes:

  • imageUrl should have a 3:2 ratio, for example 1200x800.
  • You can include more than one embed. Add one per page that you plan to share.

Step 3: Wire the SDK and call ready()#

When the UI is mounted, the app should tell the host that it is ready. If you forget this, the splash screen stays on top.

text
1// src/App.tsx
2import { useEffect } from 'react'
3import { sdk } from '@farcaster/miniapp-sdk'
4
5export default function App() {
6  useEffect(() => {
7    sdk.actions.ready()
8  }, [])
9
10  return (
11    <main style={{
12      width: 424,
13      height: 695,
14      maxWidth: '100%',
15      maxHeight: '100dvh',
16      margin: '0 auto',
17      padding: 16,
18      color: '#fff',
19      background: '#121212',
20      border: '1px solid #2a2a2a',
21      borderRadius: 20,
22      boxShadow: '0 10px 40px rgba(0,0,0,.5)'
23    }}>
24      <h1 style={{margin: 0, fontSize: 20}}>Your App Name</h1>
25      <p style={{opacity:.8}}>This frame matches the web Mini App view: 424x695. Make the layout responsive for mobile as well.</p>
26      <button
27        onClick={() => sdk.actions.composeCast({ text: 'Hello from my Mini App!' })}
28        style={{
29          marginTop: 12,
30          padding: '10px 14px',
31          borderRadius: 12,
32          border: '1px solid #2a2a2a',
33          background: '#1f1f1f',
34          color: '#fff',
35          cursor: 'pointer'
36        }}>
37        Compose Cast
38      </button>
39    </main>
40  )
41}

Sizing tips:

  • Target 424x695 for the web frame. Use flexible units so the same view adapts to mobile.

Step 4: Create the manifest#

Create a file at public/.well-known/farcaster.json. After you deploy, it must be reachable at https://YOUR-DOMAIN.com/.well-known/farcaster.json.

Minimal example:

text
1{
2  "miniapp": {
3    "version": "1",
4    "name": "Your App Name",
5    "homeUrl": "https://YOUR-DOMAIN.com",
6    "iconUrl": "https://YOUR-DOMAIN.com/icon-1024.png",
7    "splashImageUrl": "https://YOUR-DOMAIN.com/splash-200.png",
8    "splashBackgroundColor": "#000000",
9    "subtitle": "Short subtitle",
10    "description": "Short description for your app page.",
11    "primaryCategory": "social",
12    "tags": ["miniapp", "demo"],
13    "screenshotUrls": ["https://YOUR-DOMAIN.com/s1.png"],
14    "heroImageUrl": "https://YOUR-DOMAIN.com/og-1.91x1.png",
15    "ogTitle": "Your App Name",
16    "ogDescription": "A one sentence promo.",
17    "ogImageUrl": "https://YOUR-DOMAIN.com/og-1.91x1.png",
18    "noindex": false,
19    "requiredChains": ["eip155:8453"],
20    "requiredCapabilities": [
21      "actions.signIn",
22      "wallet.getEthereumProvider"
23    ]
24  }
25}

Verify your domain#

Open Developer Tools and generate the association values. Then extend the manifest with the block below.

text
1{
2  "accountAssociation": {
3    "header": "...base64...",
4    "payload": "...base64...",
5    "signature": "...base64..."
6  },
7  "miniapp": { /* same fields as above */ }
8}

Step 5: Deploy#

Deploy to any static or server platform, for example Vercel or Netlify. Check two things:

  1. The manifest URL responds with valid JSON and is public.
  2. The homeUrl HTML contains the fc:miniapp meta in the <head>.

Step 6: Preview and publish#

  • In Developer Tools, open Preview and paste your app URL. Confirm the card image, the button, and the in-frame view.
  • Share your app URL in Warpcast or Base. Posting the link helps indexing and discovery.
  • You can invite users to add your app by calling sdk.actions.addMiniApp().

Project layout#

text
1my-miniapp/
2├─ public/
3│  ├─ .well-known/
4│  │  └─ farcaster.json
5│  ├─ icon-1024.png
6│  ├─ splash-200.png
7│  └─ og-3x2.png
8├─ index.html            # contains fc:miniapp meta
9├─ src/
10│  ├─ App.tsx           # calls sdk.actions.ready()
11│  └─ main.tsx
12├─ package.json
13└─ vite.config.ts

Copy friendly snippets#

index.html with embed#

text
1<!doctype html>
2<html lang="en">
3  <head>
4    <meta charset="UTF-8" />
5    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6    <title>Your App Name</title>
7
8    <meta name="fc:miniapp" content='{
9      "version":"1",
10      "imageUrl":"https://YOUR-DOMAIN.com/og-3x2.png",
11      "button":{
12        "title":"Open App",
13        "action":{
14          "type":"launch_frame",
15          "name":"Your App Name",
16          "url":"https://YOUR-DOMAIN.com"
17        }
18      }
19    }' />
20  </head>
21  <body>
22    <div id="root"></div>
23    <script type="module" src="/src/main.tsx"></script>
24  </body>
25</html>

public/.well-known/farcaster.json#

text
1{
2  "accountAssociation": {
3    "header": "",
4    "payload": "",
5    "signature": ""
6  },
7  "miniapp": {
8    "version": "1",
9    "name": "Your App Name",
10    "homeUrl": "https://YOUR-DOMAIN.com",
11    "iconUrl": "https://YOUR-DOMAIN.com/icon-1024.png",
12    "splashImageUrl": "https://YOUR-DOMAIN.com/splash-200.png",
13    "splashBackgroundColor": "#000000",
14    "subtitle": "Short subtitle",
15    "description": "Short description.",
16    "primaryCategory": "social",
17    "tags": ["miniapp", "demo"],
18    "screenshotUrls": ["https://YOUR-DOMAIN.com/s1.png"],
19    "heroImageUrl": "https://YOUR-DOMAIN.com/og-1.91x1.png",
20    "ogTitle": "Your App Name",
21    "ogDescription": "Promo sentence.",
22    "ogImageUrl": "https://YOUR-DOMAIN.com/og-1.91x1.png",
23    "noindex": false,
24    "requiredChains": ["eip155:8453"],
25    "requiredCapabilities": [
26      "actions.signIn",
27      "wallet.getEthereumProvider"
28    ]
29  }
30}

src/App.tsx tiny example#

text
1import { useEffect } from 'react'
2import { sdk } from '@farcaster/miniapp-sdk'
3
4export default function App() {
5  useEffect(() => { sdk.actions.ready() }, [])
6  return (
7    <button onClick={() => sdk.actions.composeCast({ text: 'Hello from my Mini App!' })}>
8      Compose Cast
9    </button>
10  )
11}

Common mistakes and quick fixes#

  • Splash never hides: call sdk.actions.ready() after your UI mounts.
  • No share card in the feed: the fc:miniapp meta is missing or invalid.
  • App does not show up in search: the manifest is incomplete or the app link was never shared.
  • Wrong image ratios: use 3:2 for the embed image and 1.91:1 for OG. Icon should be 1024x1024 and splash 200x200.
  • Domain mismatch: homeUrl in the manifest must match the live domain.

Asset sizes quick list#

  • iconUrl: 1024x1024 PNG, no alpha recommended
  • splashImageUrl: 200x200
  • ogImageUrl or heroImageUrl: 1.91:1, for example 1200x630
  • embed imageUrl: 3:2, for example 1200x800

Where to read more#

Keep reading

All articles