Skip to main content
Every variable below is read by the API from apps/api/.env, or from the environment of the API container. Everything except DATABASE_URL and AUTH_SECRET has a working default. Write a comment on its own line in these files. Compose reads KEY= # note as the value # note, because it treats # as a comment only when a space precedes it inside the value, so an empty variable with a trailing comment reaches the container holding that comment.
Three settings stop a deployment cold. AUTH_SECRET must be at least 32 characters or the API refuses to boot, and changing it signs out every user. Compose refuses to start when POSTGRES_PASSWORD or AUTH_SECRET is missing or empty from the root .env.

Required

Core

Scheduling

Every cron expression is evaluated in UTC. A CRON_ value anywhere on this page that is not a cron expression refuses to boot, rather than leaving that schedule and every one registered after it silently unscheduled. The one exception is an empty CRON_STORE_CANARY or CRON_STORE_STATUS, which removes that schedule. See The daily pipeline and rate limits.

Collection rate limits

Raising either value risks the host IP address being throttled by the store. See The daily pipeline and rate limits.

Egress proxy pool

Optional. With PROXY_PROVIDER left at none every store request leaves from the host address, which is what a self hosted instance wants. Point it at a provider only when one address cannot carry the collection volume. A job holds its endpoint for its whole run, so two requests to the same store never leave through one address at once, unless a job outlives the five minute hold. When the job ends, the endpoint stays paced until the requests it made fit PROXY_ENDPOINT_RPM, counted from the moment the job took it, and never less than one request interval after the last request it sent. A job that failed is paced the same way. Google Play orders its search results by the country of the address a request comes from, so a queued Google Play job for a storefront waits for a healthy pool endpoint in that country instead of leaving through one abroad, and borrows another country’s endpoint only while every endpoint in its own country is cooling down. A name search and the keyword and competitor suggestion lookups, which someone is waiting for and whose answers are never stored, still prefer their own country but take a free endpoint abroad rather than wait for a busy one. The App Store answers the same from any address and takes whichever endpoint is free first. Google Play collection for a storefront is therefore bounded by the endpoints in that country: place them where your Google Play keywords are, because a job that finds its country’s endpoints busy for longer than PROXY_ACQUIRE_TIMEOUT_MS goes back to the queue and waits its turn again. With PROXY_PROVIDER at none the store workers keep concurrency 1 behind SCRAPE_ITUNES_RPM and SCRAPE_GPLAY_RPM. Those two variables never change meaning: they describe the budget of a single egress address, which is exactly what a self hosted instance has. Credentials stay in configuration. The database records only which credential a pool endpoint uses, never the secret itself.

Residential fallback

Datacenter addresses carry the traffic. A residential gateway is an emergency path for a single request that a datacenter address was blocked on, never a primary route, because residential bandwidth is metered and costs orders of magnitude more per request.

Alerts

See Send alerts.

Email delivery

Email stays disabled until both SMTP_HOST and SMTP_FROM are set. Email is optional on a self hosted instance and mandatory on a metered one. With BILLING_ENABLED=true in production and no mail path, the API warns at boot that it can confirm no address, warn nobody before a trial ends, and recover no forgotten password. See Hosting behind TLS and a reverse proxy.

Action Center

See Work the Action Center.

Screenshot captions

See Read screenshot captions.

Data retention

0 means keep forever. Pruning runs on CRON_RETENTION.

Runtime

Two combinations are individually valid and jointly unsafe, so the API refuses to start on them rather than logging a warning nobody reads. Five more warn at startup. See Hosting and network exposure.

Authentication

See Authentication and accounts.

Entitlements

Published store status

An opt-in outbound integration, off by default. When STORE_STATUS_URL is empty no request is ever made and the poll is not even scheduled. See What leaves your deployment and Recover from a broken store parser. The poll goes through the same public only address guard that alert webhooks use, so a url resolving to a loopback, private, link local or cloud metadata address is refused at both configuration and connection time. A failed or stale poll never changes what the local canary reported.

Optional AI

See Enable the optional AI features.

Apple search popularity

Optional, off by default. With an Apple Ads API key, asobeast reads Apple’s own weekly search popularity for the App Store terms it covers instead of estimating them. See Keyword scoring.

Store consoles

Optional, off by default. Owners connect their store consoles in Integrations; these keys protect what they paste. See Read impressions and conversion from your console.

Admin surfaces

See The queue dashboard and the OpenAPI surface.

Compose only

These live in the root .env and are read by Compose, not by the API directly. See Hosting behind TLS and a reverse proxy for the overlay and for how to verify the hop count against the real chain.

Retired variables

BULL_BOARD_USER and BULL_BOARD_PASSWORD are ignored. The queue dashboard now requires a session or a personal API token of the platform operator instead of basic authentication, and the API logs a warning at boot if either variable is still set. Remove them.

Keeping this page correct

This page and the .env.example files change in the same commit. If a default here disagrees with apps/api/.env.example, the file is right and this page is a bug.
Last modified on October 31, 2026