Complete reference for every environment variable recognised by AnswerLoops.
All variables are set in your .env file (local) or in your hosting provider's environment configuration (production). Variables marked Required must be present or the app will refuse to start.
AnswerLoops uses Auth.js v5. The correct variable names are AUTH_SECRET and AUTH_URL — notNEXTAUTH_SECRET / NEXTAUTH_URL. If you are migrating from an older deployment, rename them.
PostgreSQL connection string, e.g. postgresql://user:pass@host:5432/dbname
DIRECT_DATABASE_URL
Non-pooled connection string for LISTEN/NOTIFY only. Required whenever DATABASE_URL is a pooled connection (Neon -pooler, PgBouncer, etc.) — falls back to DATABASE_URL otherwise
AUTH_SECRET
Random 32-byte secret used to sign Auth.js v5 session tokens. Generate with openssl rand -hex 32
AUTH_URL
Full public URL of your deployment, e.g. https://answerloops.com. Used by Auth.js for OAuth callbacks
ENCRYPTION_KEY
32-byte hex key used to encrypt stored API keys at rest. Generate with openssl rand -hex 32
Number of proxies between the public internet and the app. Defaults to 1. Rate limiters resolve the client IP by counting this many entries in from the right of x-forwarded-for, so a caller-supplied prefix on that header can't be used to mint a fresh bucket per request. Set to 2 for Cloudflare in front of a platform load balancer. cf-connecting-ip takes precedence when present
ORIGIN_VERIFY_SECRET
Optional. When set, every public pre-auth POST route (/api/mcp, /api/agent/*, /api/widget/chat) rejects any request missing a matching x-origin-verify header — without it, the proxy-supplied client-IP header can be spoofed by hitting the origin directly instead of through your edge proxy. Requires a matching rule on your CDN/edge proxy; see the self-hosting guide
Optional. Base URL of a dedicated dashboard subdomain (e.g. https://app.example.com) that shares the same deployment as your root domain. When set, marketing-page CTAs link there instead of a relative /dashboard path. Unset by default — most deployments serve everything from one domain
AUTH_COOKIE_DOMAIN
Optional. Shares the Auth.js session cookie across every subdomain of your apex (e.g. .example.com). Required alongside NEXT_PUBLIC_APP_URL, since a session cookie is host-only by default — without it, a user signed in on the root domain appears logged out on the app subdomain
Full service-account JSON key, as a single-line string. Authenticates outgoing replies to the Chat API.
GOOGLE_CHAT_ENDPOINT_URL
Public HTTP endpoint URL for the Chat app's connection settings. Must exactly match what's configured in Google Cloud — used to verify incoming request tokens.
Set to cloudonly on AnswerLoops' own managed SaaS deployment. Determines whether plan-tier feature gating (Discord/Slack integrations, CSAT scoring, simulation, knowledge gap dashboard, custom AI model config) applies at all. Any other value, or unset, means self-hosted: unmetered, every feature unlocked, no Stripe required
STRIPE_SECRET_KEY
Stripe secret API key. Required when DEPLOYMENT_MODE=cloud — its absence there is treated as a misconfiguration (billing shows an error state) rather than falling back to self-hosted/unlimited
STRIPE_WEBHOOK_SECRET
Signing secret for the Stripe webhook endpoint (/api/billing/webhook), used to verify subscription lifecycle events
Stripe Price IDs for each paid plan's checkout session
DEPLOYMENT_MODE was introduced to stop deployment type from being inferred from whether STRIPE_SECRET_KEY happened to be set — a missing or rotated key on the cloud deployment used to silently degrade every paying org to unmetered/unlimited instead of surfacing as a misconfiguration.
Comma-separated list of email addresses permitted to sign in. When set, only these addresses can log in — all others are rejected. Used during waitlist / private-beta mode. Leave unset to allow any authenticated user