WWebBuddyMarketplace
Install and run

Configuration

Every environment variable Adcraft reads, with required or optional status and defaults, plus the settings you change in the admin panel instead.

7 min readUpdated Oct 17, 2026Applies to Adcraft 1.0.0

On this page

Adcraft is configured in two places:

  • Environment variables hold everything about the server: the database, secrets, sign-in, storage and every provider key. They are read from .env at the project root (in development and by next start), or from the container's environment. Change them and restart.
  • The admin panel holds what an operator changes day to day without a restart: the maintenance banner, sign-ups, trial credits, plan feature switches, guardrail defaults, and the AI model catalogue with credit prices. See Admin-panel settings.

.env.example in the package lists the variables with comments. A blank value means that integration is off.

Core

Variable Required Default What it does
AUTH_SECRET Yes None Signs session tokens. Also the source of the ad-token encryption key when TOKEN_ENCRYPTION_KEY is not set. Generate with openssl rand -base64 32.
AUTH_URL Production http://localhost:3000 in .env.example Your public HTTPS address, no trailing slash. Sign-in only trusts the request host in production when this (or AUTH_TRUST_HOST=true) is set. Magic links, invitations, share links, OAuth callbacks and API file links are built from it.
DATABASE_URL Production Embedded PGlite PostgreSQL connection string. When it is set, the Docker container runs migrations on start.
PGLITE_DATA_DIR No .data/pglite in the project folder Where the embedded evaluation database keeps its files when DATABASE_URL is not set. In Docker, point it at the mounted volume (for example /data/pglite).
NEXT_PUBLIC_APP_URL No None Your public address, used where AUTH_URL is not set: the site name on the privacy policy and the ad-platform OAuth callbacks.
ADMIN_EMAILS For the first admin None Comma-separated platform admins. A listed address is an admin on every request and cannot be revoked in the panel; removing it demotes that user unless the admin flag was granted in Admin → Users. See First admin.
DEV_LOGIN No On in development 0 hides the development sign-in box. It is never shown when NODE_ENV is production, whatever this says.

Sign-in and email

Variable Default What it does
RESEND_API_KEY None Turns on magic-link sign-in, and is used for invitations, "finished" emails and deletion requests. Without it, no email is sent.
EMAIL_FROM Adcraft <onboarding@resend.dev> in code Sender for every email. The default is Resend's test sender, which is only for testing, so production must set it to an address on a domain you have verified in Resend.
AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET None "Sign in with Google". Shown when AUTH_GOOGLE_ID is set. Redirect URI: <AUTH_URL>/api/auth/callback/google.
SUPPORT_EMAIL PRIVACY_EMAIL, then support@example.com Contact address shown on the suspended-workspace page. Set it to your own address.
PRIVACY_EMAIL SUPPORT_EMAIL, then privacy@example.com Contact address on the privacy policy and Settings → Privacy, and where workspace deletion requests are emailed. Set it to your own address.

In production, set RESEND_API_KEY or the Google pair, or nobody can sign in. The privacy policy reads PRIVACY_EMAIL and the site name from AUTH_URL (or NEXT_PUBLIC_APP_URL) on each request, so these take effect on restart without a rebuild.

AI providers

Every key is optional; each one switches on the models of that provider. AI models and providers explains what each powers.

Variable Powers
ANTHROPIC_API_KEY Claude text models: concepts, copy, scripts, brief help. ANTHROPIC_AUTH_TOKEN is also accepted.
FAL_KEY The default image models, all built-in video models and background removal
OPENAI_API_KEY GPT Image 2.5 models and GPT text models
XAI_API_KEY Grok Imagine Image 2.0 (keys start xai-)
REPLICATE_API_TOKEN Replicate models (two examples ship disabled)
RUNWAYML_API_SECRET Runway Gen-4 models (ship disabled)
HEYGEN_API_KEY AI presenters, avatars, digital twins, looks, the presenter library, HeyGen voices, voice cloning and design
ELEVENLABS_API_KEY Voice-over for presenter videos, and ElevenLabs voices in the voice library
GEMINI_API_KEY, GROQ_API_KEY, TOGETHER_API_KEY, MISTRAL_API_KEY, DEEPSEEK_API_KEY, OPENROUTER_API_KEY Not used on their own. Name one of these as the key of an OpenAI-compatible text model you add in Admin → Models.

Note

XAI_API_KEY is for xAI's Grok. GROQ_API_KEY is for the unrelated Groq inference service. They are easy to confuse.

File storage

Variable Default What it does
LOCAL_STORAGE_DIR .data/files in the project folder; /data/files in the Docker image Where uploads and generated media are written when R2 is not configured. Must be on persistent storage.
R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET None Store media in a Cloudflare R2 bucket instead. All four must be set. Create the bucket first, then an R2 API token with object read and write access. Admin → Providers shows the bucket name from R2_BUCKET.
R2_PUBLIC_BASE None Optional public or CDN address for the bucket, used for a few provider-facing links such as voice previews. Most files are still served through /api/files, which checks that the viewer belongs to the workspace.

Storage supports Cloudflare R2 only; there is no setting for another S3-compatible endpoint.

Background jobs

Variable What it does
INNGEST_EVENT_KEY Sends jobs to Inngest Cloud. Without it, jobs run inside the web process.
INNGEST_SIGNING_KEY Lets Inngest call /api/inngest securely. Set it together with the event key.
INNGEST_DEV Local only: use the Inngest Dev Server. Remove in production.

See Background jobs for what changes with Inngest.

Backups

Variable Default What it does
BACKUP_RETENTION_DAYS 14 How long nightly dumps are kept
BACKUP_DIR .data/backups in the project folder Where dumps go when R2 is not configured. In Docker, use a path on the volume, such as /data/backups.
R2_BACKUP_BUCKET R2_BUCKET A separate R2 bucket for dumps

The nightly backup only runs when Inngest is configured. See Backups.

Billing

Variable What it does
STRIPE_SECRET_KEY Turns on real payments. Without it, purchases are simulated in development; in production they are refused unless ALLOW_SIMULATED_BILLING is true.
ALLOW_SIMULATED_BILLING true lets a production install without STRIPE_SECRET_KEY simulate purchases, granting plans and credits with no payment. Only for a demo site that should hand out free credits. Leave it unset otherwise.
STRIPE_WEBHOOK_SECRET Signing secret of the /api/stripe/webhook endpoint
STRIPE_PRICE_STARTER_MONTH, STRIPE_PRICE_STUDIO_MONTH, STRIPE_PRICE_AGENCY_MONTH Monthly price IDs for the three plans
STRIPE_PRICE_STARTER_YEAR, STRIPE_PRICE_STUDIO_YEAR, STRIPE_PRICE_AGENCY_YEAR Read by the code, but the billing page only offers monthly plans in 1.0.0
STRIPE_PRICE_TOPUP One-time price for the credit top-up

See Selling it as SaaS.

Ad platforms

Without these, each platform uses a built-in sandbox. See Publishing and performance.

Variable What it does
META_APP_ID, META_APP_SECRET Meta (Facebook and Instagram) Marketing API
META_PAGE_ID Default Facebook Page for Meta ads. Optional: a Page can also be chosen on each campaign.
TIKTOK_APP_ID, TIKTOK_APP_SECRET TikTok Marketing API
GOOGLE_ADS_CLIENT_ID, GOOGLE_ADS_CLIENT_SECRET, GOOGLE_ADS_DEVELOPER_TOKEN Google Ads API. All three are needed.
GOOGLE_ADS_LOGIN_CUSTOMER_ID Optional manager (MCC) account ID
TOKEN_ENCRYPTION_KEY Base64 of 32 random bytes. Encrypts ad-platform tokens. Defaults to a key derived from AUTH_SECRET.

Observability

Variable What it does
SENTRY_DSN Also send unhandled server errors to Sentry. They are always listed at Admin → Errors.
NEXT_PUBLIC_APP_VERSION Version shown by /api/health and recorded with errors

Rendering and advanced

Usually left blank.

Variable Default What it does
FFMPEG_PATH The binary from ffmpeg-static, then ffmpeg on the PATH Use your own FFmpeg build
REMOTION_BROWSER_EXECUTABLE Remotion's Chrome Headless Shell Use an installed Chrome or Chromium for video rendering and website screenshots
ADCRAFT_REMOTION_BUNDLE_DIR A folder in the system temp directory Where the video composition bundle is cached
HEYGEN_API_BASE, HEYGEN_UPLOAD_BASE, ELEVENLABS_API_BASE, RUNWAY_API_BASE The providers' public API addresses Override a provider's API address
NEXT_PUBLIC_APP_URL None Fallback for the OAuth callback address when AUTH_URL is not set
PORT, HOSTNAME 3000 and 0.0.0.0 in the Docker image Listening port and address

Demo mode

Variable What it does
DEMO_MODE true adds two one-click buttons to the sign-in page, Explore the ad studio and Explore the admin panel, and seeds a sample workspace and sample customers on first start (about 25 MB of files, no AI calls). Demo accounts use the reserved demo.invalid domain and are read-only: every change, generation, render, purchase, email and publish is refused on the server. Real accounts are unaffected.
DEMO_ASSETS_DIR Optional. Where the seed reads its sample images and videos. Defaults to the files shipped in the image.

Note

The demo admin sees only the demo world, never real workspaces, emails or money. Real admins see everything except the demo world, so sample customers do not inflate your numbers.

Admin-panel settings

These live in the database and are changed by a platform admin, with no restart:

Where What
Admin → Settings & flags Maintenance banner, sign-ups on or off, trial credits, plan feature switches (product video, UGC, publishing), guardrail defaults (monthly provider cost cap, spend approval threshold, HeyGen voice slots, rate limit). See Platform settings.
Admin → Models & pricing Which AI models are offered, the default per kind, their credit prices, and custom models. See Managing models.

Workspace owners have their own settings under Settings → Guardrails: monthly credit limit, spend approval threshold, "finished" emails and approval before publishing.

Provider keys are not editable in the admin panel; Admin → Providers shows which ones are set.

A complete production example

.env
# Core
DATABASE_URL=postgres://user:password@db-host:5432/adcraft
AUTH_SECRET=base64-32-bytes
AUTH_URL=https://ads.example.com
ADMIN_EMAILS=you@example.com
TOKEN_ENCRYPTION_KEY=base64-32-bytes

# Sign-in and email
RESEND_API_KEY=re_...
EMAIL_FROM=Your Studio <login@ads.example.com>
SUPPORT_EMAIL=support@example.com
PRIVACY_EMAIL=privacy@example.com
AUTH_GOOGLE_ID=
AUTH_GOOGLE_SECRET=

# AI
ANTHROPIC_API_KEY=sk-ant-...
FAL_KEY=...
HEYGEN_API_KEY=...
ELEVENLABS_API_KEY=...

# Jobs
INNGEST_EVENT_KEY=...
INNGEST_SIGNING_KEY=...

# Storage (or mount a volume at /data and skip these)
R2_ACCOUNT_ID=...
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
R2_BUCKET=your-bucket

# Billing
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE_STARTER_MONTH=price_...
STRIPE_PRICE_STUDIO_MONTH=price_...
STRIPE_PRICE_AGENCY_MONTH=price_...
STRIPE_PRICE_TOPUP=price_...