Skip to content
Docs menu · Configuration

Self-hosting

Self-Hosting Configuration Reference

The environment variables a self-hosted AnyReplay deployment reads for the API, ingest and dashboard, including build-time values and limits you can tune.

Each service reads its own environment file — for example /etc/anyreplay/api.env, ingest.env and web.env — rather than sharing one, because ingest faces the public internet and should hold nothing the others need. Variables already set in the environment take precedence over the file. Never commit real values; the ones below are names and defaults only.

API

VariableDefaultPurpose
NODE_ENVdevelopmentSet to production.
API_PORT4000Listening port.
WEB_ORIGINhttp://localhost:3000The dashboard origin(s), comma-separated, allowed to call the API.
JWT_ACCESS_SECRET, JWT_REFRESH_SECRET—Two separate random secrets of at least 32 characters (openssl rand -hex 32). The API refuses to start with a shorter one.
DATABASE_URL—PostgreSQL connection string. Required in production; the API refuses to start without it.
STORAGE_DIR./.dev-storageWhere recordings live on the filesystem. Must be the same location for the API and ingest.
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, GOOGLE_REDIRECT_URI—Google sign-in. Absent means the button is not offered.
RATE_LIMIT_PER_MINUTE600Requests per minute per source address. 0 disables it.
RATE_LIMIT_AUTH_PER_MINUTE20Sign-in, sign-up and invitation attempts per minute.
RATE_LIMIT_REFRESH_PER_MINUTE240Session refreshes per minute per source address. Every page load in every open tab uses one, and an office behind one address shares the budget.
REFRESH_REUSE_GRACE_SECONDS30How long a refresh token that has just been rotated still answers with the replacement it was rotated into, rather than being treated as a replay. Covers tabs waking together and a laptop resuming. 0 restores strict single-use, at the cost of signing people out for races they cannot avoid.
RETENTION_SWEEP_INTERVAL_MS21600000How often expired recordings are deleted (six hours). 0 keeps everything for ever.
RETENTION_BATCH_SIZE200Sessions deleted per sweep batch.
PRIVACY_JOB_INTERVAL_MS30000How often pending privacy requests are picked up and their recordings deleted. 0 disables the worker, and requests stay pending.
CLOSURE_GRACE_DAYS30Days between an owner closing an organisation and its data being deleted. An owner can cancel the closure until then.
CLOSURE_SWEEP_INTERVAL_MS3600000How often organisations past their grace period are deleted (hourly). 0 disables it, and closed organisations are kept.
TRANSLATION_PROVIDER, TRANSLATION_API_KEY, TRANSLATION_MODELopenaiThe model that translates recorded sessions: openai (the default, gpt-5-nano), anthropic, fal, or none. Only the key is needed for the default; OPENAI_API_KEY is accepted in its place. Without a key the player says translation is not configured.
TRANSLATION_REASONING_EFFORTminimalReasoning budget for models that have one. Translating an interface string needs none, and reasoning tokens are billed as output. off omits the parameter.
SENTRY_DSN, SENTRY_TRACES_SAMPLE_RATEOffError reporting. Request bodies, cookies, visitor IPs and recordings are never sent.
EMAIL_PROVIDER, EMAIL_FROM, EMAIL_REGIONnoneOutgoing mail, for example through Amazon SES (ses). With none, messages are written to the service log instead of sent.
SALES_EMAIL, USAGE_EMAIL_SIGNER, USAGE_NOTIFY_INTERVAL_MS—Who usage emails come from and reply to, and how often usage is checked (15 minutes).
ONBOARDING_EMAIL_INTERVAL_MS600000How often the API looks for someone to welcome or an organisation due a setup tip (10 minutes). 0 turns the welcome and the tips off.

Ingest

VariableDefaultPurpose
INGEST_PORT4001Listening port.
DATABASE_URL—The same database as the API. Required in production.
STORAGE_DIR./.storageThe same location as the API.
MAX_CHUNK_BYTES524288Largest chunk accepted (512 KB); larger ones get 413.
RATE_LIMIT_PER_VISITOR_PER_MINUTE120Requests per minute from one device: project key and visitor id, or key and address for identify and assets. One recorder sends 12–30.
RATE_LIMIT_PER_KEY_PER_MINUTE12000Ceiling for one project key across all its devices.
RATE_LIMIT_PER_IP_PER_MINUTE6000Ceiling for one source address. High, because an office or a mobile carrier puts many devices behind one address.
RATE_LIMIT_MAX_TRACKED_KEYS100000Most keys each limiter remembers; the least recently seen is forgotten first.
MAX_ASSET_BYTES3145728Largest app image accepted (3 MB): from the React Native SDK, or from an app built from web pages, which uploads the images it ships.
MAX_ASSETS_PER_PROJECT500Distinct images one project may store.
MAX_ASSET_STORAGE_BYTES209715200Total image storage per project (200 MB).
PROJECT_CACHE_TTL_MS60000How long a project's key, status and allowed domains are cached.
PROJECT_REVALIDATE_MS5000How soon a project is re-read when ingest is about to refuse a request over its domains or apps, so a domain or app allowed from the dashboard is let in within seconds. Also caps how often a refused project can reach the database.
ORG_QUOTA_CACHE_TTL_MS15000How long plan limits and counters are cached, so an upgrade takes effect quickly.
SENTRY_DSNOffError reporting for ingest.

Dashboard

VariableWhen readPurpose
PORTRun timeThe port next start listens on.
NEXT_PUBLIC_API_URLBuild timeYour API's public URL.
NEXT_PUBLIC_INGEST_URLBuild timeYour ingest URL. Used in generated snippets.
NEXT_PUBLIC_CDN_URLBuild timeWhere the recorder bundle is served, including /v1. Used in generated snippets.

Configurations that refuse to start

  • A JWT secret shorter than 32 characters.
  • NODE_ENV=production with no DATABASE_URL. Without it the services would use an embedded, single-process database that two services cannot share safely.
  • An unsupported Node.js version.

A service that refuses to boot says why in its log. For what else to check, see the overview.