Miniapp Multi-Environment Deployment: Implementation Guide
Related ADR: Miniapp Multi-Environment Deployment Model
Overview
This guide walks through setting up the full multi-environment deployment for the Emerge miniapp.
Prerequisites
- Access to Vercel dashboard
- Access to Farcaster account(s) for signing manifests
- Access to domain DNS (for custom domain)
- Ngrok account (free tier works, paid for stable subdomain)
Phase 1: Fix Staging Credentials (Priority)
Staging is currently broken because it's missing Farcaster credentials.
1.1 Generate Staging Credentials
Option A: Warpcast Mobile App (recommended)
- Open Warpcast mobile app
- Go to Settings → Advanced → Enable Developer Mode
- Go to Settings → Developer → Domains
- Enter domain:
stg.q-miniapp.emerge.pizza - Press "Generate domain manifest"
- Copy the
accountAssociationoutput
Option B: Warpcast Web Dev Tool
- Go to Warpcast Mini Apps Manifest Tool
- Enter domain:
stg.q-miniapp.emerge.pizza - Sign with a Farcaster account you control
- Copy the output:json
{ "header": "eyJ...", "payload": "eyJ...", "signature": "0x..." }
1.2 Add to Secrets
Add to config/environments/secrets/.env.secrets.local:
# Staging Farcaster Credentials
SECRET_FARCASTER_STG_HEADER=eyJ...
SECRET_FARCASTER_STG_PAYLOAD=eyJ...
SECRET_FARCASTER_STG_SIGNATURE=0x...1.3 Update miniapp.env
The staging section already exists but is missing credentials:
[staging]
URL=https://stg.q-miniapp.emerge.pizza
MINIAPP_URL=https://stg.q-miniapp.emerge.pizza
INGRESS=https://stg.q-miniapp.emerge.pizza
BADGE=STAGING
APP_ICON=https://stg.q-miniapp.emerge.pizza/logo.webp
BYPASS_MAINTENANCE=true
# ADD THESE:
FARCASTER_HEADER=${SECRET_FARCASTER_STG_HEADER}
FARCASTER_PAYLOAD=${SECRET_FARCASTER_STG_PAYLOAD}
FARCASTER_SIGNATURE=${SECRET_FARCASTER_STG_SIGNATURE}1.4 Deploy and Verify
# Rebuild env files
pnpm build:env --profile staging
# Deploy to staging (or push to staging branch)
# Then verify manifest:
curl https://stg.q-miniapp.emerge.pizza/.well-known/farcaster.json | jqConfirm accountAssociation is populated with the new credentials.
Phase 2: Local Development with Ngrok
2.1 Set Up Ngrok
Option A: Free ngrok (random subdomain each time)
ngrok http 3338- Downside: Domain changes each session, need new Farcaster credentials each time
- Only use for quick tests
Option B: Stable subdomain (recommended)
# With ngrok paid plan or free .ngrok.pizza domain
ngrok http 3338 --domain=emerge-dev.ngrok.pizza2.2 Generate Ngrok Credentials
- Use Warpcast mobile (Settings → Developer → Domains) or web tool
- Enter your stable ngrok domain:
emerge-dev.ngrok.pizza - Sign with dev bot account (
@embot37) - Add to secrets:env
SECRET_FARCASTER_NGROK_HEADER=eyJ... SECRET_FARCASTER_NGROK_PAYLOAD=eyJ... SECRET_FARCASTER_NGROK_SIGNATURE=0x...
2.3 Update Default Section
Update miniapp.env [default] section:
[default]
# Update URL to ngrok
URL=https://emerge-dev.ngrok.pizza
INGRESS=https://emerge-dev.ngrok.pizza
# Update Farcaster credentials for ngrok
FARCASTER_HEADER=${SECRET_FARCASTER_NGROK_HEADER}
FARCASTER_PAYLOAD=${SECRET_FARCASTER_NGROK_PAYLOAD}
FARCASTER_SIGNATURE=${SECRET_FARCASTER_NGROK_SIGNATURE}
BADGE=LOCAL
# ... rest of defaults2.4 Local Development Workflow
Terminal 1 - Start ngrok:
ngrok http 3338 --domain=emerge-dev.ngrok.pizzaTerminal 2 - Start dev server:
cd apps/miniapp
pnpm devVerify:
curl https://emerge-dev.ngrok.pizza/.well-known/farcaster.json | jqPhase 3: Production Custom Domain
3.1 Choose Domain
Options:
app.emerge.pizza(subdomain of existing domain)emerge.app(if available)- Keep
emerge-mini-app.vercel.app(not recommended for production)
3.2 Configure Vercel
- Go to Vercel Dashboard → Project → Settings → Domains
- Add domain:
app.emerge.pizza - Vercel will show DNS configuration
3.3 Configure DNS
Add record to your DNS provider:
Type: CNAME
Name: app
Value: cname.vercel-dns.com
TTL: 300Or for apex domain:
Type: A
Name: @
Value: 76.76.21.21
TTL: 3003.4 Generate Production Credentials
- Use Warpcast mobile (Settings → Developer → Domains) or web tool
- Enter:
app.emerge.pizza(your chosen domain) - Sign with production bot account (
@emergebot) - Add to secrets:env
SECRET_FARCASTER_PROD_HEADER=eyJ... SECRET_FARCASTER_PROD_PAYLOAD=eyJ... SECRET_FARCASTER_PROD_SIGNATURE=0x...
3.5 Update Production Section
[production]
URL=https://app.emerge.pizza
MINIAPP_URL=https://app.emerge.pizza
INGRESS=https://app.emerge.pizza
FARCASTER_HEADER=${SECRET_FARCASTER_PROD_HEADER}
FARCASTER_PAYLOAD=${SECRET_FARCASTER_PROD_PAYLOAD}
FARCASTER_SIGNATURE=${SECRET_FARCASTER_PROD_SIGNATURE}
# ... rest of production config3.6 Redirect Old Domain
In Vercel, set up redirect from emerge-mini-app.vercel.app to new domain:
- Go to Settings → Domains
- Click on
emerge-mini-app.vercel.app - Set as redirect to
app.emerge.pizza
Phase 4: Environment-Specific Bot Accounts
4.1 Create Bot Accounts
Create Farcaster accounts for each environment:
| Account | Environment | Purpose |
|---|---|---|
@emergebot | Production | Real user interactions |
@emergebot-stg | Staging | Pre-production testing |
@embot37 | Local/Dev | Developer testing (existing) |
4.2 Configure Neynar Per Environment
Each bot needs its own Neynar configuration:
# Add to secrets per environment
SECRET_NEYNAR_STG_API_KEY=...
SECRET_NEYNAR_STG_SIGNER_UUID=...
SECRET_NEYNAR_STG_BOT_FID=...
SECRET_NEYNAR_PROD_API_KEY=...
SECRET_NEYNAR_PROD_SIGNER_UUID=...
SECRET_NEYNAR_PROD_BOT_FID=...4.3 Update miniapp.env
[staging]
NEYNAR_API_KEY=${SECRET_NEYNAR_STG_API_KEY}
NEYNAR_SIGNER_UUID=${SECRET_NEYNAR_STG_SIGNER_UUID}
NEYNAR_BOT_FID=${SECRET_NEYNAR_STG_BOT_FID}
[production]
NEYNAR_API_KEY=${SECRET_NEYNAR_PROD_API_KEY}
NEYNAR_SIGNER_UUID=${SECRET_NEYNAR_PROD_SIGNER_UUID}
NEYNAR_BOT_FID=${SECRET_NEYNAR_PROD_BOT_FID}Verification Checklist
Per Environment
- [ ] Domain resolves correctly
- [ ]
/.well-known/farcaster.jsonreturns valid manifest - [ ]
accountAssociationis populated - [ ] App loads in Warpcast mini-app viewer
- [ ] Bot can post casts (if applicable)
Test Commands
# Check manifest for each environment
curl https://stg.q-miniapp.emerge.pizza/.well-known/farcaster.json | jq '.accountAssociation'
curl https://test.q-miniapp.emerge.pizza/.well-known/farcaster.json | jq '.accountAssociation'
curl https://app.emerge.pizza/.well-known/farcaster.json | jq '.accountAssociation'
# Local (with ngrok running)
curl https://emerge-dev.ngrok.pizza/.well-known/farcaster.json | jq '.accountAssociation'Troubleshooting
Manifest Returns Empty accountAssociation
Cause: Environment variables not set or secrets not loaded
Fix:
# Rebuild env files
pnpm build:env --profile <environment>
# Verify env vars are set
grep FARCASTER apps/miniapp/.env"Domain mismatch" Error in Warpcast
Cause: Signed domain doesn't match hosting domain
Fix: Regenerate credentials with exact domain match (including/excluding www)
Ngrok Domain Not Working
Cause: Ngrok session expired or wrong domain
Fix:
# Use stable domain flag
ngrok http 3338 --domain=your-stable-domain.ngrok.pizza
# Verify it's running
curl -I https://your-stable-domain.ngrok.pizzaQuick Reference
Credential Generation
Warpcast Mobile (recommended):
- Settings → Advanced → Enable Developer Mode
- Settings → Developer → Domains
- Enter exact domain (no protocol, no trailing slash)
- Press "Generate domain manifest"
- Copy header, payload, signature to secrets
Warpcast Web:
- Open Mini Apps Manifest Tool
- Enter exact domain (no protocol, no trailing slash)
- Sign with appropriate account
- Copy header, payload, signature to secrets
Environment → Domain Mapping
| Profile | Domain | Vercel Branch |
|---|---|---|
local-docker | emerge-dev.ngrok.pizza | N/A |
staging | stg.q-miniapp.emerge.pizza | staging |
test | test.q-miniapp.emerge.pizza | test |
production | app.emerge.pizza | main |
