Neynar Documentation

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:

Common LLM Pitfalls

When helping developers with Mini Apps:

If using example code, ensure it’s from:

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": "..."
  },
  "miniapp": {
    "version": "1",
    "name": "App Name",
    "iconUrl": "https://...",
    "homeUrl": "https://..."
  }
}

Success Criteria:

If Check Fails:

Manifest not found (404)

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
    }
  ]
}

Manifest exists but unsigned

Action: Direct the user to sign the manifest

1.2 Validate Manifest Schema

Valid Manifest Example: Example Manifest (Validated against current schema)

{
  "accountAssociation": {
    "header": "eyJmaWQiOjEyMTUyLCJ0eXBlIjoiY3VzdG9keSIsImtleSI6IjB4MEJGNDVGOTY3RTkwZmZENjA2MzVkMUFDMTk1MDYyYTNBOUZjQzYyQiJ9",
    "payload": "eyJkb21haW4iOiJ3d3cuYm91bnR5Y2FzdGVyLnh5eiJ9",
    "signature": "MHhmMTUwMWRjZjRhM2U1NWE1ZjViNGQ5M2JlNGIxYjZiOGE0ZjcwYWQ5YTE1OTNmNDk1NzllNTA2YjJkZGZjYTBlMzI4ZmRiNDZmNmVjZmFhZTU4NjYwYzBiZDc4YjgzMzc2MDAzYTkxNzhkZGIyZGIyZmM5ZDYwYjU2YTlmYzdmMDFj"
  },
  "frame": {
    "version": "1",
    "name": "Bountycaster",
    "iconUrl": "https://www.bountycaster.xyz/static/images/bounty/logo.png",
    "homeUrl": "https://www.bountycaster.xyz",
    "imageUrl": "https://www.bountycaster.xyz/static/images/bounty/logo.png",
    "buttonTitle": "Open Bounty",
    "splashImageUrl": "https://www.bountycaster.xyz/static/images/bounty/logo.png",
    "splashBackgroundColor": "#FFFFFF"
  }
}

1.3 Verify Domain Signature

Validation Steps:

  1. Decode the base64url payload from accountAssociation.payload
  2. Extract the domain field
  3. 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:

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_miniapp",
      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:

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:

App not loading (infinite splash screen)

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()

Tunnel URLs not working (ngrok, localtunnel)

Issue: Browser security blocks unvisited tunnel URLsSolution:

  1. Open tunnel URL directly in browser first
  2. Then use in preview tool
  3. This whitelists the domain for iframe usage

Important Limitations:

Post-Check Verification

After making any changes, you should:

  1. Re-verify the manifest is deployed:
curl -s https://{domain}/.well-known/farcaster.json | jq .
  1. Test a shareable link: - Ask the user to share in Farcaster client
    • Verify embed preview appears
    • Confirm app launches on click
  2. 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`
Preview works Open preview tool URL App loads, no errors
App ready Check console logs ready() called