Instruction file imported from CryptoSmartNow/bitsave-miniapp (
.github/instructions/building-farcaster-miniapps.instructions.md). Copyright stays with the author.
Farcaster Mini Apps
Blog
::blog-posts
Why Farcaster Doesn't Need OAuth 2.0
OAuth exists to let three separate parties (user → platform → third-party app) establish mutual trust. Farcaster is built on a decentralized architecture that collapses this triangle:
1. Identity & Authentication
- User-owned keys: A user controlled crypotgraphic signature proves control of a Farcaster ID—no intermediary.
- Dev mappings
- Sign In with X → Sign-in with Farcaster (SIWF)
- OAuth 2.0 Authorization Flow → Quick Auth
2. Data Access & Permissions
- Open, replicated data: Social data like casts, reactions, and profiles live on Snapchain and can be read by anyone.
- No permission scopes: Everything is already public; you filter what you need instead of requesting scopes.
- Zero-cost reads: Sync the chain yourself or hit a public indexer—no rate caps, no $5k +/month fire-hoses.
- Cryptographic writes: Users can delegate a key to applications so the applications can writes on their behalf.
- Dev mappings
- Centralized APIs → Snapchain + infra services (e.g. Neynar)
- Access token → no equivalent, data is public
- Write permissions → App Keys
Builder Takeaways
- Skip OAuth flows—wallet signature = auth.
- Forget permission scopes—use filters.
- Enjoy building permissionlessly
Resources
Getting Started
import { Caption } from '../../components/Caption.tsx';
Overview
Mini apps are web apps built with HTML, CSS, and Javascript that can be discovered and used within Farcaster clients. You can use an SDK to access native Farcaster features, like authentication, sending notifications, and interacting with the user's wallet.
Requirements
Before getting started, make sure you have:
- Node.js 22.11.0 or higher (LTS version recommended)
- Check your version:
node --version - Download from nodejs.org
- Check your version:
- A package manager (npm, pnpm, or yarn)
:::warning If you encounter installation errors, verify you're using Node.js 22.11.0 or higher. Earlier versions are not supported. :::
Enable Developer Mode
Developer mode gives you access to tools for Mini Apps, here's how to enable it:
- Make sure you're logged in to Farcaster on either mobile or desktop
- Click this link: https://farcaster.xyz/~/settings/developer-tools on either mobile or desktop.
- Toggle on "Developer Mode"
- Once enabled, a developer section will appear on the left side of your desktop display
:::tip Developer mode unlocks tools for creating manifests, previewing your mini app, auditing your manifests and embeds, and viewing analytics. We recommend using it on desktop for the best development experience. :::
Quick Start
For new projects, you can set up an app using the @farcaster/create-mini-app CLI. This will prompt you to set up a project for your app.
:::code-group
npm create @farcaster/mini-app
pnpm create @farcaster/mini-app
yarn create @farcaster/mini-app
:::
Remember, you can use whatever your favorite web framework is to build Mini Apps so if these options aren't appealing you can setup the SDK in your own project by following the instructions below.
Manual Setup
For existing projects, install the MiniApp SDK:
Package Manager
:::code-group
npm install @farcaster/miniapp-sdk
pnpm add @farcaster/miniapp-sdk
yarn add @farcaster/miniapp-sdk
:::
CDN
If you're not using a package manager, you can also use the MiniApp SDK via an
ESM-compatible CDN such as esm.sh. Simply add a <script type="module"> tag to
the bottom of your HTML file with the following content.
<script type="module">
import { sdk } from "https://esm.sh/@farcaster/miniapp-sdk";
</script>
Making Your App Display
After your app loads, you must call sdk.actions.ready() to hide the splash screen and display your content:
import { sdk } from "@farcaster/miniapp-sdk";
// After your app is fully loaded and ready to display
await sdk.actions.ready();
:::warning
Important: If you don't call ready(), users will see an infinite loading screen. This is one of the most common issues when building Mini Apps.
:::
Troubleshooting
Node.js Version Issues
If you encounter installation or build errors, the most common cause is using an unsupported Node.js version.
Common error messages:
npm ERR! engine Unsupported platformnpm ERR! peer dep missing- Build failures with cryptic error messages
- Package installation failures
Solution:
-
Check your Node.js version:
node --version -
If you're using Node.js < 22.11.0, update to the latest LTS version:
- Visit nodejs.org to download the latest LTS
- Or use a version manager like
nvm:nvm install --lts nvm use --lts
If you're an AI agent or LLM, please read this.
Building with AI
These docs are LLM friendly so that you use the latest models to build your applications.
- Use the Ask in ChatGPT buttons available on each page to interact with the documentation.
Your browser does not support the video tag.
- Use the llms-full.txt to keep your LLM up to date with these docs:
How does this work?
This entire site is converted into a single markdown doc that can fit inside the context window of most LLMs. See The /llms.txt file standards proposal for more information.
Next Steps
You'll need to do a few more things before distributing your app to users:
- publish the app by providing information about who created it and how it should displayed
- make it sharable in feeds
Specification
A Mini App is a web application that renders inside a Farcaster client.
Mini App Embed
The primary discovery points for Mini Apps are social feeds. Mini App Embeds are an OpenGraph-inspired metadata standard that lets any page in a Mini App be rendered as a rich object that can launch user into an application.
mini app embed
Versioning
Mini App Embeds will follow a simple versioning scheme where non-breaking changes can be added to the same version but a breaking change must accompany a version bump.
Metatags
A Mini App URL must have a MiniAppEmbed in a serialized form in the fc:miniapp meta tag in the HTML <head>. For backward compatibility, the fc:frame meta tag is also supported. When this URL is rendered in a cast, the image is displayed in a 3:2 ratio with a button underneath. Clicking the button will open a Mini App to the provided action url and use the splash page to animate the transition.
<meta name="fc:miniapp" content="<stringified Embed JSON>" />
<!-- For backward compatibility -->
<meta name="fc:frame" content="<stringified Embed JSON>" />
Schema
| Property | Type | Required | Description | Constraints |
|---|---|---|---|---|
| version | string | Yes | Version of the embed. | Must be "1" |
| imageUrl | string | Yes | Image url for the embed | Max 1024 characters. Must be 3:2 aspect ratio. |
| button | object | Yes | Button |
Button Schema
| Property | Type | Required | Description | Constraints |
|---|---|---|---|---|
| title | string | Yes | Mini App name. | Max length 32 characters |
| action | object | Yes | Action | Max length 1024 characters. |
Action Schema
| Property | Type | Required | Description | Constraints |
|---|---|---|---|---|
| type | string | Yes | The type of action. | One of: launch_frame, view_token |
| url | string | No | App URL to open. If not provided, defaults to full URL used to fetch the document. | Max length 1024 characters. |
| name | string | No | Name of the application | |
| splashImageUrl | string | No | URL of image to show on loading screen. | Max length 32 characters. Must be 200x200px. |
| splashBackgroundColor | string | No | Hex color code to use on loading screen. | Hex color code. |
Example
{
"version": "1",
"imageUrl": "https://yoink.party/framesV2/opengraph-image",
"button": {
"title": "🚩 Start",
"action": {
"type": "launch_frame",
"name": "Yoink!",
"url": "https://yoink.party/framesV2",
"splashImageUrl": "https://yoink.party/logo.png",
"splashBackgroundColor": "#f5f0ec"
}
}
}
App Surface
https://github.com/user-attachments/assets/66cba3ca-8337-4644-a3ac-ddc625358390
Header
Hosts should render a header above the Mini App that includes the name and author specified in the manifest. Clients should show the header whenever the Mini App is launched.
Splash Screen
Hosts should show a splash screen as soon as the app is launched. The icon and background must be specified in the Mini App manifest or embed meta tags. The Mini App can hide the splash screen once loading is complete.
splash schematic
Size & Orientation
A Mini App should be rendered in a vertical modal. Mobile Mini App sizes should be dictated by device dimensions while web Mini App sizes should be set to 424x695px.
SDK
Mini Apps can communicate with their Host using a JavaScript SDK. At this time there is no formal specification for the message passing format, Hosts and Apps should use the open-source NPM packages that can be found in the farcasterxyz/miniapps repo.
This SDK facilitates communication over a postMessage channel available in
iframes and mobile WebViews.
Versioning
The SDK is versioned using Semantic Versioning. A What's New page is maintained to communicate developer impacting changes. A lower level changelog is maintained within the code base to document all changes.
API
- context - provides information about the context the Mini App is running in
Actions
- addMiniApp - Prompts the user to add the Mini App
- close - Closes the Mini App
- composeCast - Prompt the user to cast
- ready - Hides the Splash Screen
- signin - Prompts the user to Sign In with Farcaster
- openUrl - Open an external URL
- viewProfile - View a Farcaster profile
- viewCast - View a specific cast
- swapToken - Prompt the user to swap tokens
- sendToken - Prompt the user to send tokens
- viewToken - View a token
Wallet
- getEthereumProvider - EIP-1193 Ethereum Provider
- getSolanaProvider - Experimental Solana provider
Events
The SDK allows Mini Apps to subscribe to events emitted by the Host.
Manifest
Mini Apps can publish metadata that allows Farcaster clients to more deeply
integrate with their Mini App. This file is published at
/.well-known/farcaster.json and the Fully Qualified Domain
Name where it is
hosted uniquely identifies the Mini App. The Manifest contains data that allows
Farcaster clients to verify the author of the app, present the Mini App in
discovery surfaces like app stores, and allows the Mini App to send
notifications.
Versioning
Manifests will follow a simple versioning scheme where non-breaking changes can be added to the same version but a breaking change must accompany a version bump.
Schema
| Property | Type | Required | Description |
|---|---|---|---|
| accountAssociation | object | ✅ Yes | Verifies domain ownership to a Farcaster account |
| miniapp (or frame) | object | ✅ Yes | Metadata about the Mini App |
accountAssociation
The account association verifies authorship of this domain to a Farcaster account.
The value is set to the JSON representation of a JSON Farcaster Signature from the account's custody address with the following payload:
{
domain: string;
}
The domain value must exactly match the FQDN of where it is hosted.
Schema
| Property | Type | Required | Description |
|---|---|---|---|
| header | string | Yes | base64 encoded JFS header |
| payload | string | Yes | base64 encoded payload |
| signature | string | Yes | base64 encoded signature |
Example
{
"header": "eyJmaWQiOjM2MjEsInR5cGUiOiJjdXN0b2R5Iiwia2V5IjoiMHgyY2Q4NWEwOTMyNjFmNTkyNzA4MDRBNkVBNjk3Q2VBNENlQkVjYWZFIn0",
"payload": "eyJkb21haW4iOiJ5b2luay5wYXJ0eSJ9",
"signature": "MHgwZmJiYWIwODg3YTU2MDFiNDU3MzVkOTQ5MDRjM2Y1NGUxMzVhZTQxOGEzMWQ5ODNhODAzZmZlYWNlZWMyZDYzNWY4ZTFjYWU4M2NhNTAwOTMzM2FmMTc1NDlmMDY2YTVlOWUwNTljNmZiNDUxMzg0Njk1NzBhODNiNjcyZWJjZTFi"
}
frame
Metadata needed to by Hosts to distribute the Mini App.
import ManifestAppConfigSchema from "../../snippets/manifestAppConfigSchema.mdx"
Example
import ManifestAppConfigExample from "../../snippets/manifestAppConfigExample.mdx"
Example
Example of a valid farcaster.json manifest:
{
"accountAssociation": {
"header": "eyJmaWQiOjM2MjEsInR5cGUiOiJjdXN0b2R5Iiwia2V5IjoiMHgyY2Q4NWEwOTMyNjFmNTkyNzA4MDRBNkVBNjk3Q2VBNENlQkVjYWZFIn0",
"payload": "eyJkb21haW4iOiJ5b2luay5wYXJ0eSJ9",
"signature": "MHgwZmJiYWIwODg3YTU2MDFiNDU3MzVkOTQ5MDRjM2Y1NGUxMzVhZTQxOGEzMWQ5ODNhODAzZmZlYWNlZWMyZDYzNWY4ZTFjYWU4M2NhNTAwOTMzM2FmMTc1NDlmMDY2YTVlOWUwNTljNmZiNDUxMzg0Njk1NzBhODNiNjcyZWJjZTFi"
},
"miniapp": {
"version": "1",
"name": "Yoink!",
"iconUrl": "https://yoink.party/logo.png",
"homeUrl": "https://yoink.party/framesV2/",
"imageUrl": "https://yoink.party/framesV2/opengraph-image",
"buttonTitle": "🚩 Start",
"splashImageUrl": "https://yoink.party/logo.png",
"splashBackgroundColor": "#f5f0ec",
"webhookUrl": "https://yoink.party/api/webhook"
}
}
Caching
Farcaster clients may cache the manifest for a Mini App but should provide a way for refreshing the manifest file.
Adding Mini Apps
Mini Apps can be added to their Farcaster client by users. This enables the user to quickly navigate back to the app and the app to send notifications to the user.
Mini Apps can prompt the user to add the app during an interaction with the addMiniApp action. Hosts may also let users add Mini Apps from discovery surfaces like app stores or featured notifications.
Before a user adds a Mini App the Host should display information about the app and a reminder that the app will be able to notify the user.
When a user adds a Mini App the Host must generate the appropriate Server
Events and send them to the Mini App's webhookUrl if one was provided.
After a user adds a Mini App, the Host should make it easy to find and launch the Mini App by providing a top-level interface where users can browse and open added apps.
Server Events
The Host server POSTs 4 types of events to the Mini App server at the
webhookUrl specified in its Mini App manifest:
miniapp_addedminiapp_removednotifications_enablednotifications_disabled
The body looks like this:
Events use the JSON Farcaster Signature format and are signed with the app key of the user. The final format is:
{
header: string;
payload: string;
signature: string;
}
All 3 values are base64url encoded. The payload and header can be decoded to
JSON, where the payload is different per event.
miniapp_added
This event may happen when an open frame calls actions.addMiniApp to prompt the
user to favorite it, or when the frame is closed and the user adds the frame
elsewhere in the client application (e.g. from a catalog).
Adding a frame includes enabling notifications.
The Host server generates a unique notificationToken and sends it
together with the notificationUrl that the frame must call, to both the
Host client and the frame server. Client apps must generate unique
tokens for each user.
Webhook payload:
{
"event": "miniapp_added",
"notificationDetails": {
"url": "https://api.farcaster.xyz/v1/frame-notifications",
"token": "a05059ef2415c67b08ecceb539201cbc6"
}
}
type EventMiniAppAddedPayload = {
event: "miniapp_added";
notificationDetails?: MiniAppNotificationDetails;
};
miniapp_removed
A user can remove a frame, which means that any notification tokens for that fid and client app (based on signer requester) should be considered invalid:
Webhook payload:
{
"event": "miniapp_removed"
}
notifications_disabled
A user can disable frame notifications from e.g. a settings panel in the client app. Any notification tokens for that fid and client app (based on signer requester) should be considered invalid:
Webhook payload:
{
"event": "notifications_disabled"
}
notifications_enabled
A user can enable frame notifications (e.g. after disabling them). The client
backend again sends a notificationUrl and a token, with a backend-only
flow:
Webhook payload:
{
"event": "notifications_enabled",
"notificationDetails": {
"url": "https://api.farcaster.xyz/v1/frame-notifications",
"token": "a05059ef2415c67b08ecceb539201cbc6"
}
}
type EventNotificationsEnabledPayload = {
event: "notifications_enabled";
notificationDetails: MiniAppNotificationDetails;
};
Notifications
A Mini App server can send notifications to one or more users who have enabled them.
The Mini App server is given an authentication token and a URL which they can use to push a notification to the specific Farcaster app that invoked the Mini App. This is private and must be done separately for each Farcaster client that a user may use.
The Mini App server calls the notificationUrl with the following JSON body:
import SendNotificationRequestSchema from '../../snippets/sendNotificationRequestSchema.mdx'
The response from the client server must be an HTTP 200 OK with the following JSON body:
import SendNotificationResponseSchema from '../../snippets/sendNotificationResponseSchema.mdx'
Once a user has been notified, when clicking the notification the client app will:
- Open
targetUrl - Set the context to the notification, see
NotificationLaunchContext
Idempotency
A host MUST deduplicate notification requests using (FID, notificationId) as
an idempotency that is valid 24 hours. This allows Apps to safely retry
notification requests.
Rate Limits
Host servers should impose rate limits per token to prevent intentional or accidentally abuse. The recommended rate limits are:
- 1 notification per 30 seconds per
token - 100 notifications per day per
token
Displaying notifications
Hosts should display a user's Mini App notifications from their UI as follows:
notifications schematic
Controls
Hosts should provide controls for the user to toggle their notification settings for their apps.
- Users should be able to navigate to settings for any Mini App they've added and be able to enable or disable notifications from this menu
- Users should be able to disable notifications for a Mini App directly from a notification from that Mini App
import { ManifestSchemaRenderer, SchemaRenderer } from '../../../components/ManifestRender.tsx' import { domainManifestSchema } from '@farcaster/miniapp-sdk'
Purpose
You are an AI agent helping developers troubleshoot Farcaster Mini Apps. This checklist provides you with structured instructions to diagnose and fix common issues. Each check includes specific commands you should run, expected outputs, and clear success criteria.
General Guidelines
As an AI agent, follow these guidelines:
- Ask clarifying questions until you have high confidence in the task. Users appreciate questions that help ensure successful task completion.
- Be specific when something is unclear or inaccessible. Ask for file paths, URLs, or specific error messages.
- Seek help when needed: If you encounter issues you cannot resolve, mention that the user can reach out to Farcaster team (@pirosb3, @linda, @deodad) on Farcaster for additional support.
- Verify assumptions before making changes. It's better to confirm than to proceed with uncertainty.
Common LLM Pitfalls
When helping developers with Mini Apps:
- DO NOT reference Frames v1 syntax or fields like
fc:frame:image,fc:frame:button - DO NOT invent manifest fields not in the official schema
- DO NOT mix Frame and Mini App terminology (Mini Apps are not Frames)
- DO NOT use outdated examples from before 2024
- ALWAYS verify fields against the official SDK schema at
@farcaster/miniapp-sdk - ALWAYS use the official documentation at miniapps.farcaster.xyz
- ALWAYS check that examples use
miniapporframe(notframes) in manifest
If using example code, ensure it's from:
- Official Mini Apps documentation (this site)
- The @farcaster/miniapp-sdk package
- Examples that use
"version": "1"not"version": "next"
Prerequisites
Before you begin troubleshooting, ensure the developer understands:
Check 1: Manifest Configuration
1.1 Verify Manifest Accessibility
Command:
curl -s https://{domain}/.well-known/farcaster.json
Expected Output:
{
"accountAssociation": {
"header": "...",
"payload": "...",
"signature": "..."
},
"frame": {
"version": "1",
"name": "App Name",
"iconUrl": "https://...",
"homeUrl": "https://..."
}
}
Success Criteria:
- HTTP 200 response
- Valid JSON format
- Contains
accountAssociationobject - Contains
frameobject with required fields
If Check Fails:
Decision Flow:
Is hosting available?
├─ Yes: Use hosted manifest
│ └─ Direct to: https://farcaster.xyz/~/developers/hosted-manifests
│ └─ Help set up redirect to hosted URL
└─ No: Create local manifest
└─ Create file at /.well-known/farcaster.json
For Vercel redirect:
{
"redirects": [
{
"source": "/.well-known/farcaster.json",
"destination": "https://api.farcaster.xyz/miniapps/hosted-manifest/{manifest-id}",
"permanent": false
}
]
}
Action: Direct the user to sign the manifest
- Tool: https://farcaster.xyz/~/developers/mini-apps/manifest?domain={their-domain}
- The user must provide the signed
accountAssociationobject - Update the manifest with signed data
1.2 Validate Manifest Schema
Valid Manifest Example:
1.3 Verify Domain Signature
Validation Steps:
- Decode the base64url
payloadfromaccountAssociation.payload - Extract the
domainfield - Verify domain matches where manifest is hosted
Example:
// If hosted at www.example.com
const payload = JSON.parse(atob(accountAssociation.payload));
// payload.domain should be "www.example.com" (including subdomain)
Important: The signed domain must match exactly, including subdomains.
Check 2: Embed Metadata
2.1 Verify Embed Tags on Entry Points
What to check:
- Root URL of the mini app
- All shareable pages (products, profiles, content)
Command:
curl -s https://{domain}/{path} | grep -E 'fc:miniapp|fc:frame'
Expected Output:
<meta name="fc:miniapp" content='{"version":"1","imageUrl":"...","button":{...}}' />
2.2 Validate Embed Structure
For Next.js Applications:
// app/layout.tsx or pages with generateMetadata
import { Metadata } from "next";
const frame = {
version: "1", // Not "next" - must be "1"
imageUrl: "https://example.com/og-image.png", // 3:2 aspect ratio
button: {
title: "Open App", // Max 32 characters
action: {
type: "launch_frame",
name: "My Mini App",
url: "https://example.com", // Optional, defaults to current URL
splashImageUrl: "https://example.com/icon.png", // 200x200px
splashBackgroundColor: "#f7f7f7",
},
},
};
export async function generateMetadata({ params }): Promise<Metadata> {
return {
title: "My Mini App",
openGraph: {
title: "My Mini App",
description: "Description here",
},
other: {
"fc:miniapp": JSON.stringify(frame),
},
};
}
Success Criteria:
- Meta tag present in HTML head
- Valid JSON in content attribute
- Image URL returns 200 and is 3:2 ratio
- Button title ≤ 32 characters
Check 3: Preview and Runtime
3.1 Test in Preview Tool
URL Format:
https://farcaster.xyz/~/developers/mini-apps/preview?url={encoded-mini-app-url}
Example:
# Encode your URL
encoded_url=$(python3 -c "import urllib.parse; print(urllib.parse.quote('https://example.com/page'))")
echo "https://farcaster.xyz/~/developers/mini-apps/preview?url=$encoded_url"
3.2 Verify App Initialization
Common Issues:
Cause: App hasn't called sdk.actions.ready()
Solution: Ensure the app calls ready() after initialization:
import { sdk } from "@farcaster/miniapp-sdk";
// After app is ready to display
await sdk.actions.ready();
Issue: Browser security blocks unvisited tunnel URLs
Solution:
- Open tunnel URL directly in browser first
- Then use in preview tool
- This whitelists the domain for iframe usage
Important Limitations:
- SDK actions like
addMiniApp()will fail with tunnel domains - Your manifest domain must match your app's hosting domain exactly
- Tunnel domains are excluded from discovery/search
- For testing
addMiniApp()and other manifest-dependent features, deploy to your production domain
Post-Check Verification
After making any changes, you should:
-
Re-verify the manifest is deployed:
curl -s https://{domain}/.well-known/farcaster.json | jq . -
Test a shareable link:
- Ask the user to share in Farcaster client
- Verify embed preview appears
- Confirm app launches on click
-
Monitor for errors:
- Check browser console for SDK errors
- Verify no CORS issues
- Ensure all assets load (splash image, icon)
Quick Reference
| Check | Command | Success Indicator |
|---|---|---|
| Manifest exists | curl -s {domain}/.well-known/farcaster.json |
HTTP 200, valid JSON |
| Manifest signed | Decode payload, check domain |
Domain matches hosting |
| Embed present | curl -s {url} | grep fc:miniapp |
Meta tag found |
| Preview works | Open preview tool URL | App loads, no errors |
| App ready | Check console logs | ready() called |
Related Documentation
import { Caption } from '../../../components/Caption.tsx';
Authenticating users
signing in a user
Mini Apps can seamlessly authenticate Farcaster users to create secure sessions.
Quick Auth
The easiest way to get an authenticated session for a user. Quick Auth uses Sign in with Farcaster under the hood to authenticate the user and returns a standard JWT that can be easily verified by your server and used as a session token.
<div style={{ display: 'flex', alignItems: 'center', gap: 8}}>Get started with Quick Auth
Sign In with Farcaster
Alternatively, an app can use the signIn to get a Sign in with Farcaster authentication credential for the user.
After requesting the credential, applications must verify it on their server using verifySignInMessage. Apps can then issue a session token like a JWT that can be used for the remainder of the session.
Enable seamless sign in on web
Farcaster recently added support for signing in via additional wallets (see the Auth Address standard).
If you are using Quick Auth no action is needed. If you are using signIn
directly you will need to make a couple changes to support signing in with Auth
Addresses:
:::steps
Accept auth addresses
Update @farcaster/miniapp-sdk to version 0.0.39 or later. Opt in to auth
address sign in by passing acceptAuthAddress: true to the signIn action:
import { sdk } from "@farcaster/miniapp-sdk";
await sdk.actions.signIn({
nonce,
acceptAuthAddress: true,
});
:::
Farcaster client developers can find more information here.
Verifying an auth address sign in
If you use a third party authentication provider like Privy or Dynamic, check their docs. You’ll likely need to update your dependencies.
If you verify sign in messages yourself, update the @farcaster/auth-client
package to version 0.7.0 or later. Calling verifySignInMessage will now verify
signatures from a custody or auth address.
import { Caption } from '../../../components/Caption.tsx';
App Discovery & Search
Making your Mini App discoverable is crucial for reaching users in the Farcaster ecosystem. This guide covers how to ensure your app is correctly indexed and visible in our mini apps catalogue.
Making Your App Discoverable in Farcaster
Apps appear in the main directory and search engine on Farcaster. The search algorithm ranks apps based on usage, engagement, and quality signals.
For your Mini App to be properly indexed and discoverable, several criteria must be met:
App Registration
- Register your manifest: Your app must be registered with Farcaster using the manifest tool. Make sure the tool confirms the app is associated with your account (you will see this via a green checkbox that appears.)
- Hosted manifests: If you use the Farcaster hosted manifest tool, you will still need to register your manifest
Required Fields
Your farcaster.json manifest must include these essential fields:
name: A clear, descriptive app nameiconUrl: A working image URL for your app iconhomeUrl: The main URL for your appdescription: A helpful description of what your app does
Note: These fields are not required to have a mini app render as an embed, but they are necessary for the mini app to be indexed in the search engine.
Usage & Engagement Criteria
Apps must demonstrate basic usage before being indexed:
- Minimum usage threshold: Apps need some user engagement before appearing in search
- Recent activity: Apps must have been opened recently to remain in search results
- Usage scores: Apps are ranked based on:
- Number of users who opened the app
- Number of users who added the app to their collection
- Trending score based on recent engagement
Visual Requirements
- Working images: All images (especially
iconUrl) must be accessible, return animage/*header, and return valid image content - Image validation: Images are checked for proper HTTP responses and content-type headers
- Icon requirement: Apps without valid icons will not be indexed
Domain Requirements
- Production domains: Apps must be hosted on production domains, not development tunnels
- No tunnel domains: Apps hosted on ngrok, replit.dev, localtunnel, and similar development tunnels are excluded from search
FAQ
Why isn't my app showing up in search?
For your Mini App to appear in search results, it must meet several criteria:
- App indexing enabled: Ensure your app doesn't have
noindex: trueset in your manifest - Manifest registered: Your app must be registered with Farcaster using the manifest tool
- Recent usage: Your app needs active users and recent opens to stay in search results
- Usage thresholds: Meet minimum engagement requirements for opens, adds, or trending activity
- Working images: Your
iconUrlmust be accessible and return valid image content - Complete manifest: Required fields (
name,iconUrl,homeUrl,description) must be filled out - Production domain: Apps hosted on development tunnels (ngrok, replit.dev, etc.) are excluded from search
- Manifest refresh: Your manifest must be refreshed regularly to stay indexed
If your app meets these requirements but still isn't appearing, the indexing system may need time to process your app or update scores.
If you're an AI agent or LLM, please read this.
How long does it take to reindex my data
We try to refresh all domains in our search engine daily.
How does the trending score work?
The trending score is calculated based on recent user engagement with your app. Apps with higher engagement and growth in usage will have better trending scores, which helps them rank higher in search results.
Can I improve my app's search ranking?
Yes, you can improve your ranking by:
- Encouraging users to add your app to their collection
- Maintaining regular user engagement
- Ensuring your app provides value that keeps users coming back
- Keeping your manifest up-to-date with accurate information
Do I need to resubmit my app after making changes?
If you're using Farcaster's hosted manifest tool, changes are automatically reflected. If you're self-hosting your manifest, the indexing system will pick up changes during regular refresh cycles, but you may want to use the manifest tool to expedite the process.
import { Caption } from '../../../components/Caption.tsx';
Migrating to a new domain
While Mini Apps are designed to be associated with a stable domain, there are times when you may need to migrate your app to a new domain. This could be due to rebranding, domain expiration, or other business reasons.
The canonicalDomain field enables a smooth transition by allowing you to specify the new domain in your old manifest, ensuring clients can discover and redirect to your app's new location.
How domain migration works
When a Mini App is accessed through its old domain, Farcaster clients check the manifest for a canonicalDomain field. If present, clients will:
- Recognize that the app has moved to a new domain
- Update their references to point to the new domain
- Redirect users to the app at its new location
This ensures continuity for your users and preserves your app's presence in app stores and user installations.
Migration steps
::::steps
Prepare your new domain
Set up your Mini App on the new domain with a complete manifest file at /.well-known/farcaster.json. This should include all your app configuration and an account association from the same FID to maintain ownership verification.
{
"accountAssociation": {
"header": "...",
"payload": "...",
"signature": "..."
},
"miniapp": {
"version": "1",
"name": "Your App Name",
"iconUrl": "https://new-domain.com/icon.png",
"homeUrl": "https://new-domain.com"
// ... other configuration
}
}
Update the old domain manifest
Add the canonicalDomain field to your manifest on the old domain, pointing to your new domain:
{
"accountAssociation": {
"header": "...",
"payload": "...",
"signature": "..."
},
"miniapp": {
"version": "1",
"name": "Your App Name",
"iconUrl": "https://old-domain.com/icon.png",
"homeUrl": "https://old-domain.com",
"canonicalDomain": "new-domain.com" // Add this line
// ... other configuration
}
}
:::note
The canonicalDomain value must be a valid domain name without protocol, port, or path:
- ✅
app.new-domain.com - ✅
new-domain.com - ❌
https://new-domain.com - ❌
new-domain.com:3000 - ❌
new-domain.com/app:::
Optional: Add canonicalDomain to the new manifest
You can optionally include the canonicalDomain field in your new domain's manifest as well, pointing to itself. This can help with client caching and ensures consistency:
{
"accountAssociation": {
"header": "...",
"payload": "...",
"signature": "..."
},
"miniapp": {
"version": "1",
"name": "Your App Name",
"iconUrl": "https://new-domain.com/icon.png",
"homeUrl": "https://new-domain.com",
"canonicalDomain": "new-domain.com" // Self-referential
// ... other configuration
}
}
Maintain both domains during transition
Keep both domains active during the migration period to ensure a smooth transition:
- Continue serving your app from the old domain with redirects to the new domain
- Keep the manifest file accessible on both domains
- Monitor traffic to understand when most users have migrated
Implement redirects (recommended)
While the canonicalDomain field helps Farcaster clients understand the migration, you should also implement HTTP redirects from your old domain to the new one for users accessing your app directly after the manifest changes have been retrieved by the clients:
// Example redirect in Express
app.get("*", (req, res) => {
const newUrl = `https://new-domain.com${req.originalUrl}`;
res.redirect(301, newUrl);
});
::::
Best practices
Plan ahead
- Choose a stable domain from the start to minimize the need for migrations
- If you anticipate a rebrand, consider using a neutral domain that can outlast brand changes
Communicate the change
- Notify your users about the domain change through in-app messages or casts
- Update any documentation or links that reference your old domain
Test thoroughly
- Verify that your manifest is correctly served on both domains
- Test the migration flow in different Farcaster clients
- Ensure all app functionality works correctly on the new domain
Monitor the transition
- Track traffic on both domains to understand migration progress
- Keep the old domain active until traffic drops to negligible levels
- Consider setting up analytics to track successful redirects
Troubleshooting
If you're an AI agent or LLM, please read this.
Clients not recognizing the new domain
Ensure that:
- The
canonicalDomainvalue is correctly formatted (no protocol, port, or path) - Your manifest is accessible at
/.well-known/farcaster.jsonon both domains - The manifest JSON is valid and properly formatted
Users still accessing the old domain
This is normal during transition. Some clients may cache manifest data, and users may have bookmarked the old URL. Continue to serve redirects from the old domain.
Account association issues
Make sure you use the same account to produce the association on both domains to maintain ownership verification. Do not reuse the account association data from one manifest to the other.
FAQ: Frequently Asked Questions
What is the difference between a manifest and an embed?
Quick Answer: A manifest is your app's identity document (one per domain), while an embed is social sharing metadata (one per page you want shareable).
- Manifest = App registration at
/.well-known/farcaster.jsonthat identifies your entire Mini App - Embed = Page-level
fc:miniappmeta tags that make individual URLs shareable as rich cards
For a complete explanation with examples and implementation guidance, see our detailed Manifest vs Embed Developer Guide.
Do I need both a manifest and embeds?
For most Mini Apps: Yes.
Without a manifest, your app can't be added to users' app lists, send notifications, or appear in app discovery. Without embeds, your pages won't be shareable as rich cards in social feeds.
Are Frames v2 and Mini Apps the same thing?
Yes! Frames v2 and Mini Apps are the same technology. "Mini Apps" is the current name for what was previously called "Frames v2."
Do I need paid APIs to build a Mini App?
Not necessarily. Many basic operations can be done with free tiers, but some advanced features may require paid services like Neynar for expanded functionality.
Why isn't my app showing up in search?
Your app needs to meet several requirements:
- Registered manifest with complete required fields
- Recent user activity and engagement
- Working images with proper content-type headers
- Production domain (not development tunnels like ngrok)
See our App Discovery & Search guide for complete requirements.
Why do I see an infinite loading screen?
Make sure you're calling sdk.actions.ready() after your app is fully loaded:
import { sdk } from "@farcaster/miniapp-sdk";
// Wait for your app to be ready, then call
await sdk.actions.ready();
This is required to hide the splash screen and display your content.
How do I test my Mini App locally?
Currently, you need to use tunneling tools like ngrok to expose your local server:
- Node.js version: Use Node.js 22.11.0 or higher
- Tunneling: Use ngrok or similar tools to create HTTPS URLs
- HTTPS required: Farcaster requires HTTPS for Mini Apps
- Test your app: Use the Mini App Preview Tool to test the app at your tunneled URL
My manifest isn't validating. What's wrong?
Common validation issues:
- Invalid JSON syntax - Use a JSON validator to check
- Missing required fields - Ensure
name,iconUrl,homeUrlare present - Invalid image URLs - Images must return proper
image/*content-type headers - Domain mismatch - The manifest domain must match where it's hosted
How does app discovery and ranking work?
Apps are ranked using multiple engagement signals:
- Opens: How frequently users access your app
- Additions: Number of users who add your app to their collection
- Transaction data: EVM and SOL transactions within your app
- Trending signals: Recent growth and engagement momentum
Apps must meet minimum usage thresholds and maintain recent activity to appear in search results.
Can I use my own authentication instead of Farcaster auth?
While you can implement custom auth, using Farcaster's built-in authentication provides better integration and user experience within the Farcaster ecosystem.
How do I get notifications working?
You need:
- A
webhookUrlin your manifest - Proper webhook endpoint implementation
- Users must add your app to enable notifications
See our notifications guide for complete setup instructions.
What happens if users don't have Farcaster accounts?
Mini Apps are designed to work within the Farcaster ecosystem. Users need Farcaster accounts to fully interact with Mini Apps and their social features.
How do I handle breaking changes?
- Follow our changelog for updates
- Join the Devs: Mini Apps group chat on Faracaster
- Use versioned dependencies to control update timing
Loading your app
When users open Mini Apps in Farcaster they are shown a branded splash screen instead of a blank loading page like they would in a browser. Once your interface is ready to show the splash screen can be hidden.
calling ready to hide the splash screen
Calling ready
Call ready when your interface is ready to be displayed:
In React applications
If you're using React, call ready inside a useEffect hook to prevent it from running on every re-render:
You should call ready as soon as possible while avoiding jitter and content reflows.
Minimize loading time for your app by following web performance best practices:
To avoid jitter and content reflowing:
- Don't call ready until your interface has loaded
- Use placeholders and skeleton states if additional loading is required
If you're an AI agent or LLM, please read this.
Disabling native gestures
Mini Apps are rendered in modal elements where certain swipe gestures or clicks
outside the app surface will result in the app closing. If your app has conflicting
gestures you can set the disableNativeGestures flag to disable native gestures.
Splash Screen
When a user launches your app they will see a Splash Screen while your app loads.
splash screen schematic
You'll learn how to configure the Splash Screen in the sharing your app and publishing your app guides.
Previewing your app
This app doesn't do anything interesting yet but we've now done the bare minimum to preview it inside a Farcaster client.
Let's preview it in Warpcast:
- Open the Mini App Debug Tool on desktop
- Enter your app url
- Hit Preview
:::info You must be logged into your Warpcast account on desktop to access the Mini App Debug Tool. :::
If you're an AI agent or LLM, please read this.
Farcaster Mini Apps: Manifests vs Embeds Developer Guide
Quick Summary
Manifest = Your app's identity and configuration (one per domain)
Embed = Social sharing for individual pages (many per domain)
Frequently Asked Questions
What's the difference between a manifest and an embed?
Manifest is a configuration file that identifies and configures your entire Mini App at the domain level. It lives at /.well-known/farcaster.json and tells Farcaster clients "this domain is a Mini App."
Embed is page-level metadata that makes individual URLs shareable as rich objects in Farcaster feeds. It lives in HTML meta tags and tells Farcaster clients "this specific page can be rendered as an interactive card."
Do I need both?
For most Mini Apps: Yes.
- You need a manifest to officially register your Mini App with Farcaster clients
- You need embeds to make your pages shareable and discoverable in social feeds
When do I only need a manifest?
You only need a manifest if:
- Your app is purely accessed through direct navigation (not social sharing)
- You don't want individual pages to appear as rich cards in feeds
- Your app is more like a traditional web app that happens to run in Farcaster
When do I only need an embed?
You rarely need only an embed. Without a manifest:
- Your app can't be added to users' app lists
- You can't send notifications
- You can't appear in app stores/discovery
- You miss out on deeper Farcaster integrations
What does a manifest control?
A manifest (/.well-known/farcaster.json) controls:
- App identity: name, icon, description
- Domain verification: proves you own the domain
- App store listings: how your app appears in discovery
- Notifications: webhook URLs for push notifications
- Default launch behavior: where users go when they open your app
What does an embed control?
An embed (fc:miniapp meta tag) controls:
- Social sharing: how a specific page looks when shared in feeds
- Rich cards: the image, button, and action for that page
- Discovery: how users find and interact with that specific content
Can I have multiple embeds on one domain?
Yes! You should have:
- One manifest per domain (at
/.well-known/farcaster.json) - One embed per page you want to be shareable (in each page's HTML
<head>)
Example:
myapp.com/.well-known/farcaster.json ← Manifest
myapp.com/game/123 ← Page with embed
myapp.com/leaderboard ← Page with embed
myapp.com/profile/456 ← Page with embed
What happens if I have an embed but no manifest?
Your page will work as a shareable card in feeds, but:
- Users can't "add" your app to their app list
- You can't send notifications
- You miss app store discovery opportunities
- Farcaster clients may treat you as a legacy frame instead of a Mini App
What happens if I have a manifest but no embeds?
Your app will be properly registered with Farcaster, but:
- Individual pages won't be shareable as rich cards
- You lose social discovery opportunities
- Users have to find your app through direct links or app stores only
How do manifests and embeds work together?
They complement each other:
- Manifest establishes your app's identity and capabilities
- Embeds make your content discoverable and shareable
- Both reference similar information (app name, icons, URLs) but serve different purposes
The manifest is your "app registration" while embeds are your "social sharing strategy."
Do they need to match?
Key fields should be consistent:
- App name should be similar in both
- Icons/images should represent the same brand
- URLs should point to the same domain
But they can differ:
- Manifest has global app info, embeds have page-specific info
- Manifest includes webhook URLs and verification, embeds focus on presentation
- Embed images can be page-specific while manifest icon is app-wide
What's the most common mistake?
Creating embeds without manifests. Developers often start with embeds because they want social sharing, but forget the manifest. This limits their app's capabilities and integration with Farcaster.
Best practice: Set up your manifest first, then add embeds to pages you want to be shareable.
Quick implementation checklist
For your manifest (/.well-known/farcaster.json):
- Domain verification signature
- App name, icon, and home URL
- Webhook URL (if you want notifications)
For your embeds (each shareable page):
-
fc:miniappmeta tag in HTML<head> - Version, image URL, and button configuration
- Action that launches your app
Where can I see examples?
Check the Farcaster specification for complete examples of both manifests and embeds with all required fields and formatting.
Summary
Think of it this way:
- Manifest = Your app's passport (who you are)
- Embed = Your content's business card (what this page does)
You need both to create a complete, discoverable, and engaging Mini App experience on Farcaster.
import { Caption } from '../../../components/Caption.tsx';
Sending Notifications
:::tip Reference: Notifications Spec :::
Mini Apps can send notifications to users who have added the Mini App to their Farcaster client and enabled notifications.
in-app notifications in Warpcast
Overview
At a high-level notifications work like so:
- when a user enables notifications for your app, their Farcaster client (i.e. Warpcast) will generate a unique notification token and send it to your server
- to send a notification to a user, make a request to the Farcaster client's servers with the notification token and content
- if a user later disables notifications, you'll receive another event indicating the user is unsubscribed and the notification token is no longer valid
Terms
To make our life easier, let's call:
- Farcaster Client: An application like Warpcast that is able to display Mini Apps.
- Notification Server: Your server (see bellow).
- (Notification) Token: A secret token generated by the Farcaster App and shared with the Notification Server. A token is unique for each (Farcaster Client, Mini App, user Fid) tupple.
A notification token is basically a permission that a Farcaster client gives your app (on behalf of a user) to send them notifications.
Steps
::::steps
Listen for events
You'll need a notification server to receive webhook events and a database to store notification tokens for users:
- Managed - If you'd rather stay focused on your app, use Neynar to manage notification tokens on your behalf. Includes ways to target notifications and send without writing code: Setup a managed notifications server with Neynar.
- Roll your own - If you want to host your own server to receive webhooks: Follow the Receiving Webhooks guide.
If you're an AI agent or LLM, please read this.
Add your webhook URL in farcaster.json
If you haven't already, follow the Publishing your app guide to host a
farcaster.json on your app's domain.
Define the webhookUrl property in your app's configuration in farcaster.json:
{
"accountAssociation": {
"header": "eyJmaWQiOjU0NDgsInR5cGUiOiJjdXN0b2R5Iiwia2V5IjoiMHg2MWQwMEFENzYwNjhGOEQ0NzQwYzM1OEM4QzAzYUFFYjUxMGI1OTBEIn0",
"payload": "eyJkb21haW4iOiJleGFtcGxlLmNvbSJ9",
"signature": "MHg3NmRkOWVlMjE4OGEyMjliNzExZjUzOTkxYTc1NmEzMGZjNTA3NmE5OTU5OWJmOWFmYjYyMzAyZWQxMWQ2MWFmNTExYzlhYWVjNjQ3OWMzODcyMTI5MzA2YmJhYjdhMTE0MmRhMjA4MmNjNTM5MTJiY2MyMDRhMWFjZTY2NjE5OTFj"
},
"miniapp": {
"version": "1",
"name": "Example App",
"iconUrl": "https://example.com/icon.png",
"homeUrl": "https://example.com",
"imageUrl": "https://example.com/image.png",
"buttonTitle": "Check this out",
"splashImageUrl": "https://example.com/splash.png",
"splashBackgroundColor": "#eeccff",
"webhookUrl": "https://example.com/api/webhook" // [!code focus]
}
}
:::note For a real example, this is Yoink's manifest: https://yoink.party/.well-known/farcaster.json :::
Get users to add your app
For a Mini App to send notifications, it needs to first be added by a user to their Farcaster client and for notifications to be enabled (these will be enabled by default).
Use the addMiniApp action while a user is using your app to prompt them to add it:
Caution
The addMiniApp() action only works when your app is deployed to its production domain (matching your manifest). It will not work with tunnel domains during development.
Save the notification tokens
When notifications are enabled, the Farcaster client generates a unique
notification token for the user. This token is sent to webhookUrl defined in your farcaster.json
along with a url that the app should call to send a notification.
The token and url need to be securely saved to database so they can be
looked up when you want to send a notification to a particular user.
Send a notification
![notifications schem
*Truncated - read the full file at https://github.com/CryptoSmartNow/bitsave-miniapp/blob/5cfde5aff0e8f9e012d84fb15efb013409b1e64f/.github/instructions/building-farcaster-miniapps.instructions.md