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.jsonas 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.
1npm create vite@latest my-miniapp -- --template react-ts
2cd my-miniapp
3npm i @farcaster/miniapp-sdk
4npm run devOpen 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.
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:
imageUrlshould 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.
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:
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.
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:
- The manifest URL responds with valid JSON and is public.
- The
homeUrlHTML contains thefc:miniappmeta 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#
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.tsCopy friendly snippets#
index.html with embed#
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#
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#
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:miniappmeta 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:
homeUrlin 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#
- Farcaster Mini Apps site: https://miniapps.farcaster.xyz/ (opens in a new tab)
- Full LLMs text: https://miniapps.farcaster.xyz/llms-full.txt (opens in a new tab)
- Base docs: migrate existing apps: https://docs.base.org/mini-apps/quickstart/migrate-existing-apps (opens in a new tab)


