Pitchbar reads its configuration from the standard Laravel
.env, with overrides for some keys available via the
platform admin's App Settings page so you can swap
Stripe / mail / LLM credentials without redeploying.
Required
Variable
Why
APP_KEY
Encryption master key. Generate with php artisan key:generate. Never rotate without a re-encrypt migration.
APP_URL
Public URL, used to build widget snippets, OAuth callbacks, signed URLs.
DB_*
Postgres connection.
REDIS_HOST
Cache, sessions, queue, hot-path retrieval cache, conversation history cache.
QUEUE_CONNECTION
Set to redis in production.
SESSION_DRIVER
redis in production.
CACHE_DRIVER
redis.
WIDGET_JWT_SECRET
HS256 signing secret for visitor JWTs. โฅ 32 random bytes.
LLM provider
At least one of the following:
Variable
Provider
CLOUDFLARE_ACCOUNT_ID + CLOUDFLARE_API_TOKEN
Cloudflare Workers AI (preferred). Auto-binds Llama 3.3 70B + bge-base-en-v1.5.
OPENAI_API_KEY
OpenAI direct.
OPENROUTER_API_KEY
OpenRouter (router across many providers).
Set LLM_PROVIDER to force a binding (cloudflare,
openai, openrouter). When unset, the resolver
picks based on which keys are available, in the priority above.
Vector store
Variable
Provider
VECTORIZE_INDEX
Cloudflare Vectorize index name. Uses CLOUDFLARE_ACCOUNT_ID + token.
QDRANT_URL + QDRANT_API_KEY
Qdrant.
Set VECTOR_PROVIDER to force. Auto-binds based on
available keys (Vectorize preferred).
Crawler
Variable
Strategy
(uses CLOUDFLARE_*)
Cloudflare Browser Rendering. Preferred.
BROWSERLESS_TOKEN + BROWSERLESS_URL
Browserless fallback.
(none)
Plain HTTP. Free; no JS rendering.
Variable
Purpose
CRAWL_MAX_PAGES_PER_SOURCE
Max pages fan-out per Source. Default 500 (raised from 25 โ buyers adding 100-URL sitemaps were silently losing 75 pages). Cap applies after sitemap-index recursion + dedupe.
CRAWL_PAGE_DISPATCH_DELAY
Per-page delay (seconds) when fanning out sitemap pages so Cloudflare Browser Rendering's small per-account concurrency doesn't 429. Default 2.
CLOUDFLARE_BROWSER_RENDERING
Set to false to force the Browserless / plain-HTTP path even when Cloudflare keys are present. Default true.
RAG / retrieval
Variable
Purpose
RAG_CONFIDENCE_THRESHOLD
Default similarity threshold for newly created agents. 0.5 for Cloudflare bge-base-en-v1.5 (its ANN cosine peaks lower than OpenAI's); 0.78 for OpenAI text-embedding-3-small. Auto-resolves based on LLM_PROVIDER.
RAG_RERANK_ENABLED
Set to false to disable the bge-reranker-base cross-encoder pass. Default true when Cloudflare keys are present.
Google OAuth (Drive + Docs) โ register an OAuth client in the GCP console with drive.readonly and documents.readonly scopes.
Marketing demo widget
Variable
Purpose
MARKETING_DEMO_AGENT_ID
UUID of a published agent that powers the live demo widget on the marketing pages. Add the marketing site URL to that agent's allowed_origins.
DEMO
Set to true to open Login / Get started links in a new tab on the marketing site โ useful for reviewers exploring a CodeCanyon live demo without losing the marketing page when they hop into the app.
Queue tick (Cloudflare Worker cron)
Variable
Purpose
INTERNAL_QUEUE_TOKEN
Shared bearer secret protecting POST /api/v1/internal/queue-tick. The Cloudflare Worker cron pings this every 60s to drive the queue when in-cluster scheduling isn't available.
App Settings overrides
The app_settings singleton row stores plaintext-encrypted
overrides for:
Stripe secret + webhook secret + publishable key.
Mail driver settings.
Cloudflare / OpenAI / OpenRouter keys.
Branding (label, URL, logo).
The AppSettingsOverrideServiceProvider reads this on boot
and merges into config(). Setting things via the admin
panel is preferred for production โ you don't have to re-deploy when a
key rotates.
APP_KEY rotation requires a manual migration. The
encrypted columns in app_settings were sealed with the
old key; rotating without re-encrypting renders them unreadable.