answerLoopsanswerLoopsDocs
Reference

Environment Variables

Complete reference for every environment variable recognised by answerLoops.

This is the complete list of environment variables answerLoops reads. Use it to look up a name, find out whether it is required, and see what it controls. To see the few you need to start, read Minimum to boot in the self-hosting guide.

Set variables in your .env file (local) or in your hosting provider's environment configuration (production).

MarkerMeaning
RequiredMust be set for a working deployment
OptionalHas a default, or only switches on an extra feature
Managed service onlyUsed only on answerLoops' own hosted service; self-hosters leave it unset

answerLoops uses Auth.js v5. The variable names are AUTH_SECRET and AUTH_URL, not NEXTAUTH_SECRET / NEXTAUTH_URL. If you are migrating from an older deployment, rename them. (NEXTAUTH_URL is still honoured as a fallback for AUTH_URL when building links in emails and OAuth callbacks.)

Core and access

Core (required)

VariableDescription
DATABASE_URLRequired. PostgreSQL connection string, e.g. postgresql://<user>:<password>@<host>:5432/<database>
DIRECT_DATABASE_URLOptional. Non-pooled connection string used only for LISTEN/NOTIFY (configuration hot-reload, live team and dashboard updates). Needed whenever DATABASE_URL points at a pooled connection (a provider's pooled endpoint, PgBouncer, etc.); otherwise it falls back to DATABASE_URL
AUTH_SECRETRequired. Random 32-byte secret for the Auth.js v5 session and for channel connect flows. Generate with openssl rand -hex 32
AUTH_URLRequired. Full public URL of your deployment, e.g. https://answerloops.com. Used for sign-in callbacks and links in emails
ENCRYPTION_KEYRequired in production (NODE_ENV=production). 32-byte hex key used to encrypt stored credentials at rest. Generate with openssl rand -hex 32

Sign-in (required)

Google is the only sign-in provider answerLoops configures. Both variables are required.

VariableDescription
AUTH_GOOGLE_IDGoogle OAuth client ID
AUTH_GOOGLE_SECRETGoogle OAuth client secret

Callback URL to register: https://<your-domain>/api/auth/callback/google

DISCORD_CLIENT_ID and SLACK_CLIENT_ID below are separate: they power the "connect a Discord server" and "Add to Slack" flows inside the product, not sign-in. There is no Discord, Slack or GitHub provider for dashboard sign-in.

Networking

VariableDescription
TRUST_PROXY_HOPSOptional. Number of proxies between the public internet and the app. Defaults to 1. Set to 2 for Cloudflare in front of a platform load balancer
ORIGIN_VERIFY_SECRETOptional. A shared secret between your CDN or edge proxy and the app. Requires a matching rule at the edge; see the self-hosting guide

Public URLs and multi-domain

VariableDescription
APP_URLOptional. Public origin of the app, read at request time (changing it needs a restart, not a rebuild). Used, for example, as the server address advertised in the OpenAPI spec. Falls back to NEXT_PUBLIC_APP_URL
NEXT_PUBLIC_APP_URLOptional. Base URL of a dedicated dashboard subdomain (e.g. https://app.example.com) on the same deployment as your root domain. When set, marketing-page links go there instead of a relative /dashboard path. Most deployments serve everything from one domain and leave it unset
AUTH_COOKIE_DOMAINOptional. Shares the session cookie across subdomains of your apex (e.g. .example.com). Required alongside NEXT_PUBLIC_APP_URL, because a session cookie is host-only by default

AI providers

Platform default

VariableDescription
OPENAI_API_KEYRequired for AI features unless every workspace brings its own key. The platform-wide OpenAI key, used for AI answers, draft replies and embeddings for any workspace that has not saved its own provider key

Anthropic, Google Gemini, Groq, Mistral, xAI and OpenAI-compatible endpoints are configured per workspace in Settings → AI Model, where each workspace saves its own key. They are not read from environment variables, so ANTHROPIC_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, GROQ_API_KEY and MISTRAL_API_KEY have no effect; support for them is coming soon. Embeddings must produce 1536-dimension vectors.

Widget chat runtime

VariableDescription
COPILOTKIT_TELEMETRY_DISABLEDOptional. Opts the widget chat runtime out of its telemetry ping. Defaults to true; set to false to opt back in

Knowledge-base crawling

VariableDescription
FIRECRAWL_API_KEYOptional. Firecrawl API key; needed for URL crawl imports into the knowledge base
FIRECRAWL_API_URLOptional. Point at a self-hosted Firecrawl instance instead of the managed service

Channels

Discord

VariableDescription
DISCORD_TOKENBot token from the Discord Developer Portal. Needed on both the app service (channel picker, invite flow) and the bot service. A workspace's own saved bot token takes precedence
DISCORD_CLIENT_IDOptional. Discord application client ID. When set, onboarding offers a 1-click "Add to Discord" flow instead of asking for a manually created bot token and channel IDs
DISCORD_CLIENT_SECRETOptional. OAuth2 client secret; required together with DISCORD_CLIENT_ID for the 1-click flow
DISCORD_APPLICATION_IDOptional. Discord application ID (usually the same as DISCORD_CLIENT_ID). Required to register the /ask and /summarize slash commands
DISCORD_GUILD_IDOptional. When set, slash commands are registered for that one server (instant) instead of globally (can take up to an hour to appear)
DISCORD_CHANNEL_IDSOptional. Comma-separated channel IDs the bot watches when the workspace has no channels saved in Settings
BOT_SECRETShared secret between the bot service and the app. Each workspace gets its own in Settings; this is the environment fallback
BOT_TARGET_URLURL of the app as seen from the bot service, e.g. https://answerloops.com (no trailing slash). Defaults to http://localhost:3000

Slack

VariableDescription
SLACK_CLIENT_IDSlack app client ID; enables the 1-click "Add to Slack" install
SLACK_CLIENT_SECRETSlack app client secret; required with SLACK_CLIENT_ID
SLACK_SIGNING_SECRETSigning secret from your Slack app, needed for Events API delivery
SLACK_POLL_INTERVAL_SECONDSOptional. How often, in seconds, the app polls Slack for new messages. Defaults to 60

Google Chat

VariableDescription
GOOGLE_CHAT_SERVICE_ACCOUNT_JSONFull service-account JSON key as a single-line string, used for outgoing replies through the Chat API
GOOGLE_CHAT_ENDPOINT_URLPublic HTTP endpoint URL of the Chat app. Must exactly match what is configured in Google Cloud

GitHub

VariableDescription
GITHUB_APP_IDNumeric ID of your GitHub App
GITHUB_APP_PRIVATE_KEYThe App's PEM private key, base64-encoded (base64 -i your-app.pem | tr -d '\n')
GITHUB_WEBHOOK_SECRETWebhook secret for the GitHub App. Generate with openssl rand -hex 32 and paste without a trailing newline. /api/github/webhook returns 503 until it is set
GITHUB_APP_SLUGURL slug of your GitHub App, e.g. answerloops
GITHUB_APP_CLIENT_IDThe App's Client ID. Enable "Request user authorization (OAuth) during installation" on the App
GITHUB_APP_CLIENT_SECRETA client secret generated in the App settings; required with GITHUB_APP_CLIENT_ID

Telegram

VariableDescription
TELEGRAM_WEBHOOK_BASE_URLOptional. Overrides AUTH_URL as the base for the Telegram webhook address. Each workspace saves its own bot token in Integrations → Telegram, so there is no bot-token variable

Email (Resend, Gmail, Outlook)

VariableDescription
RESEND_API_KEYResend API key for outbound transactional email and the email ingest channel
RESEND_FROMDefault sender address for transactional email, e.g. [email protected]
RESEND_NEWSLETTER_FROMSender address for blog newsletter signup confirmations (can match RESEND_FROM)
RESEND_WEBHOOK_SECRETRequired for inbound email through Resend, and for bounce and complaint tracking. Signing secret (whsec_...) of your Resend webhook. Without it, Resend's events are not accepted; outbound replies still send
GMAIL_CLIENT_ID / GMAIL_CLIENT_SECRETOptional. Google Cloud OAuth client for the "Connect Gmail" send-only integration. Without it that feature is unavailable
GMAIL_REDIRECT_URIOptional. Override for the Gmail OAuth callback URL (defaults to <app-url>/api/email/gmail/callback)
OUTLOOK_CLIENT_ID / OUTLOOK_CLIENT_SECRETOptional. Microsoft Entra app registration for the "Connect Outlook" send-only integration. Without it that feature is unavailable
OUTLOOK_REDIRECT_URIOptional. Override for the Outlook OAuth callback URL (defaults to <app-url>/api/email/outlook/callback)
FEEDBACK_NOTIFY_EMAILOptional. Where to send an alert when someone posts product feedback. Defaults to [email protected]; set your own address on a self-hosted install

Per-workspace integrations (no environment variable)

Discourse, Circle and the Notion knowledge-base source are configured entirely per workspace. There is no platform-wide app or shared credential to set; each workspace pastes its own token or secret in Settings, and it is stored encrypted with ENCRYPTION_KEY.

IntegrationWhere it's configuredSetup guide
DiscourseIntegrations → DiscourseDiscourse
CircleIntegrations → CircleCircle
Notion KB sourceIntegrations → NotionNotion

Operations

Analytics tuning

VariableDescription
ROI_MINUTES_PER_TICKETOptional. Minutes assumed saved per deflected ticket in the ROI calculation. Defaults to 10
ROI_STAFF_HOURLY_RATEOptional. Hourly staff rate used to turn hours saved into a dollar figure. Defaults to 50

Web Push (VAPID)

Browser push notifications turn on when both keys are set. They announce new tickets and customer replies on existing ones; replies on the same ticket replace each other on the device.

VariableDescription
VAPID_PUBLIC_KEYVAPID public key
VAPID_PRIVATE_KEYVAPID private key
VAPID_EMAILOptional. Contact address in mailto: form, e.g. mailto:[email protected]

Generate a key pair with:

npx web-push generate-vapid-keys

Sentry (error tracking)

VariableDescription
SENTRY_DSNOptional. DSN from your Sentry project's Client Keys settings. Unset disables error tracking entirely; no requests to Sentry are made
SENTRY_AUTH_TOKENOptional. Only needed to upload source maps at build time
SENTRY_ORGOptional. Sentry organization slug, used with SENTRY_AUTH_TOKEN
SENTRY_PROJECTOptional. Sentry project slug, used with SENTRY_AUTH_TOKEN

Build, privacy and development

VariableDescription
CLOUDFLARE_WEB_ANALYTICSOptional. Set to true to allow Cloudflare Web Analytics on pages. Read when the config loads, so set it where the build runs
NEXT_PUBLIC_DOCS_WIDGET_TOKENOptional. Embeds a chat widget token on the built-in /docs pages. Local or dev use; the widget does not render without it
ALLOW_PRIVATE_OUTBOUND_URLSDevelopment only. Set to true to let outbound fetches reach private addresses; ignored when NODE_ENV=production
MOCK_EXTERNALSTest suites only. Replaces external services with in-process fakes; a production process refuses to run with it set

Billing and deployment mode

Everything in this section is for answerLoops' own managed service. Self-hosters leave all of it unset: your install is unmetered, every feature is unlocked, and no Stripe account is needed.

VariableDescription
DEPLOYMENT_MODEManaged service only. Set to cloud only on answerLoops' own managed deployment. It decides whether plan-tier feature gating applies at all. Any other value, or unset, means self-hosted
STRIPE_SECRET_KEYManaged service only. Stripe secret API key. Required when DEPLOYMENT_MODE=cloud; its absence there is treated as a misconfiguration (billing shows an error state)
STRIPE_WEBHOOK_SECRETManaged service only. Signing secret for the Stripe webhook endpoint (/api/billing/webhook)
STRIPE_PUBLISHABLE_KEYManaged service only. Publishable key (pk_...) for the embedded checkout form on /checkout, read at request time. NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY is still accepted as a fallback. Without either, the page shows a disabled state instead of a card form
STRIPE_PRICE_STANDARD / STRIPE_PRICE_PRO / STRIPE_PRICE_ENTERPRISEManaged service only. Stripe Price IDs for each paid plan's checkout. Each must hold the price for the plan it names: the amount shown in the app comes from the code, the amount charged from Stripe
STRIPE_PRICE_STANDARD_ANNUAL / STRIPE_PRICE_PRO_ANNUAL / STRIPE_PRICE_ENTERPRISE_ANNUALManaged service only. Yearly Price IDs for the same plans, used when a visitor picks annual billing. A plan without one declines annual checkout rather than billing the monthly price
FEEDBACK_WIDGET_ENABLEDManaged service only. Set to true or 1 to show the product feedback board. Off by default; self-hosted installs have no board

DEPLOYMENT_MODE exists so deployment type is never guessed from whether STRIPE_SECRET_KEY happens to be set. A missing or rotated key on the managed service surfaces as a misconfiguration instead of silently turning every paying workspace into an unmetered one.

Where to go next

On this page