Skip to content

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)

  1. Open Warpcast mobile app
  2. Go to Settings → Advanced → Enable Developer Mode
  3. Go to Settings → Developer → Domains
  4. Enter domain: stg.q-miniapp.emerge.pizza
  5. Press "Generate domain manifest"
  6. Copy the accountAssociation output

Option B: Warpcast Web Dev Tool

  1. Go to Warpcast Mini Apps Manifest Tool
  2. Enter domain: stg.q-miniapp.emerge.pizza
  3. Sign with a Farcaster account you control
  4. Copy the output:
    json
    {
      "header": "eyJ...",
      "payload": "eyJ...",
      "signature": "0x..."
    }

1.2 Add to Secrets

Add to config/environments/secrets/.env.secrets.local:

env
# 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:

env
[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

bash
# 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 | jq

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

bash
ngrok http 3338
  • Downside: Domain changes each session, need new Farcaster credentials each time
  • Only use for quick tests

Option B: Stable subdomain (recommended)

bash
# With ngrok paid plan or free .ngrok.pizza domain
ngrok http 3338 --domain=emerge-dev.ngrok.pizza

2.2 Generate Ngrok Credentials

  1. Use Warpcast mobile (Settings → Developer → Domains) or web tool
  2. Enter your stable ngrok domain: emerge-dev.ngrok.pizza
  3. Sign with dev bot account (@embot37)
  4. 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:

env
[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 defaults

2.4 Local Development Workflow

Terminal 1 - Start ngrok:

bash
ngrok http 3338 --domain=emerge-dev.ngrok.pizza

Terminal 2 - Start dev server:

bash
cd apps/miniapp
pnpm dev

Verify:

bash
curl https://emerge-dev.ngrok.pizza/.well-known/farcaster.json | jq

Phase 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

  1. Go to Vercel Dashboard → Project → Settings → Domains
  2. Add domain: app.emerge.pizza
  3. 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: 300

Or for apex domain:

Type: A
Name: @
Value: 76.76.21.21
TTL: 300

3.4 Generate Production Credentials

  1. Use Warpcast mobile (Settings → Developer → Domains) or web tool
  2. Enter: app.emerge.pizza (your chosen domain)
  3. Sign with production bot account (@emergebot)
  4. Add to secrets:
    env
    SECRET_FARCASTER_PROD_HEADER=eyJ...
    SECRET_FARCASTER_PROD_PAYLOAD=eyJ...
    SECRET_FARCASTER_PROD_SIGNATURE=0x...

3.5 Update Production Section

env
[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 config

3.6 Redirect Old Domain

In Vercel, set up redirect from emerge-mini-app.vercel.app to new domain:

  1. Go to Settings → Domains
  2. Click on emerge-mini-app.vercel.app
  3. Set as redirect to app.emerge.pizza

Phase 4: Environment-Specific Bot Accounts

4.1 Create Bot Accounts

Create Farcaster accounts for each environment:

AccountEnvironmentPurpose
@emergebotProductionReal user interactions
@emergebot-stgStagingPre-production testing
@embot37Local/DevDeveloper testing (existing)

4.2 Configure Neynar Per Environment

Each bot needs its own Neynar configuration:

env
# 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

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.json returns valid manifest
  • [ ] accountAssociation is populated
  • [ ] App loads in Warpcast mini-app viewer
  • [ ] Bot can post casts (if applicable)

Test Commands

bash
# 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:

bash
# 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:

bash
# Use stable domain flag
ngrok http 3338 --domain=your-stable-domain.ngrok.pizza

# Verify it's running
curl -I https://your-stable-domain.ngrok.pizza

Quick Reference

Credential Generation

Warpcast Mobile (recommended):

  1. Settings → Advanced → Enable Developer Mode
  2. Settings → Developer → Domains
  3. Enter exact domain (no protocol, no trailing slash)
  4. Press "Generate domain manifest"
  5. Copy header, payload, signature to secrets

Warpcast Web:

  1. Open Mini Apps Manifest Tool
  2. Enter exact domain (no protocol, no trailing slash)
  3. Sign with appropriate account
  4. Copy header, payload, signature to secrets

Environment → Domain Mapping

ProfileDomainVercel Branch
local-dockeremerge-dev.ngrok.pizzaN/A
stagingstg.q-miniapp.emerge.pizzastaging
testtest.q-miniapp.emerge.pizzatest
productionapp.emerge.pizzamain

Released under the MIT License.