# Open-SEO Environment Variables: Complete Configuration Guide for Every Deployment Mode

> Master Open-SEO environment variables for all deployment modes. Discover essential configuration for DATAFORSEO_API_KEY and beyond to optimize your setup.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-06-28

---

**Open-SEO requires `DATAFORSEO_API_KEY` as the sole mandatory variable for core functionality, with additional environment variables needed only for specific authentication modes, cloud deployments, or optional third-party integrations like Google Search Console and PostHog.**

The `every-app/open-seo` repository uses a comprehensive environment variable system to configure authentication strategies, API credentials, and deployment targets. All supported variables are documented in the `.env.example` file at the repository root, while the application accesses them through a centralized runtime helper in [`src/server/lib/runtime-env.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/runtime-env.ts).

## Core Required Variables

At minimum, Open-SEO needs access to the DataforSEO API to fetch ranking and backlink data.

- **`DATAFORSEO_API_KEY`** – Required for all deployment modes. This key authenticates requests to DataforSEO endpoints consumed in [`scripts/brand-lookup-cost-profile.ts`](https://github.com/every-app/open-seo/blob/main/scripts/brand-lookup-cost-profile.ts) and [`scripts/backlinks-cost-profile.ts`](https://github.com/every-app/open-seo/blob/main/scripts/backlinks-cost-profile.ts).
- **`PORT`** – Optional. Defaults to `3000` when unset. Referenced in [`vite.config.ts`](https://github.com/every-app/open-seo/blob/main/vite.config.ts) to bind the development server.

## Authentication Configuration

Open-SEO supports multiple authentication strategies controlled by the `AUTH_MODE` variable. The codebase reads these values in [`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts) and [`cli-auth.ts`](https://github.com/every-app/open-seo/blob/main/cli-auth.ts).

### Cloudflare Access Mode

When `AUTH_MODE=cloudflare_access`, the application expects Cloudflare zero-trust headers for user validation:

- **`TEAM_DOMAIN`** – Your Cloudflare Access team domain.
- **`POLICY_AUD`** – The Cloudflare Access policy audience identifier.

Both variables are validated at runtime in [`src/lib/auth.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/auth.ts).

### Hosted Mode

When `AUTH_MODE=hosted`, Open-SEO uses Better Auth for credential management:

- **`BETTER_AUTH_SECRET`** – Random hex string for token encryption (generate with `openssl rand -hex 32`).
- **`BETTER_AUTH_URL`** – The canonical URL where your auth server runs (e.g., `http://localhost:3001` for local development).

This mode also enables Google Search Console integration when OAuth credentials are provided.

## Optional Third-Party Integrations

The application conditionally enables features based on the presence of specific variables.

### Google Search Console

Required when enabling Google OAuth for search analytics:

- **`GOOGLE_CLIENT_ID`** – OAuth 2.0 client ID from Google Cloud Console.
- **`GOOGLE_CLIENT_SECRET`** – Corresponding client secret.

These credentials are documented in [`docs/SELF_HOSTING_GOOGLE_SEARCH_CONSOLE.md`](https://github.com/every-app/open-seo/blob/main/docs/SELF_HOSTING_GOOGLE_SEARCH_CONSOLE.md) and consumed during the OAuth flow initialization.

### Analytics and Monitoring

- **`POSTHOG_PUBLIC_KEY`** and **`POSTHOG_HOST`** – Enables PostHog product analytics when both are present, consumed in [`src/lib/analytics.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/analytics.ts).
- **`LOOPS_API_KEY`**, **`LOOPS_TRANSACTIONAL_VERIFY_EMAIL_ID`**, and **`LOOPS_TRANSACTIONAL_RESET_PASSWORD_ID`** – Configures Loops.email for transactional messaging, referenced in [`src/lib/email.ts`](https://github.com/every-app/open-seo/blob/main/src/lib/email.ts).

### Testing Configuration

- **`PLAYWRIGHT_CHANNEL`** – Selects browser channels for end-to-end tests in [`playwright.config.ts`](https://github.com/every-app/open-seo/blob/main/playwright.config.ts).
- **`DOMAIN_FILTER_CPU_THROTTLE`** – Controls performance throttling in [`e2e/domain-overview-filters.perf.spec.ts`](https://github.com/every-app/open-seo/blob/main/e2e/domain-overview-filters.perf.spec.ts).

## Deployment-Specific Variables

### Docker Self-Hosting

When deploying via Docker Compose:

- **`ALLOWED_HOST`** – Whitelist entry for reverse-proxy validation in [`docker-compose.yml`](https://github.com/every-app/open-seo/blob/main/docker-compose.yml).
- **`OPEN_SEO_IMAGE`** – Docker image tag specification in [`compose.yaml`](https://github.com/every-app/open-seo/blob/main/compose.yaml).

### Cloudflare Workers Production

Deploying to Cloudflare Workers requires three specific credentials used in [`drizzle-prod.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle-prod.config.ts):

- **`CLOUDFLARE_ACCOUNT_ID`** – Your Cloudflare account identifier.
- **`CLOUDFLARE_DATABASE_ID`** – The D1 database ID for SQL storage.
- **`CLOUDFLARE_API_TOKEN`** – API token with Workers and D1 permissions.

These variables are marked as non-nullable in the Drizzle configuration using the `!` operator, causing the build to fail if missing.

### SEO and Site Configuration

- **`SITE_URL`** or **`VITE_SITE_URL`** – Base URL for sitemap generation in [`web/scripts/generate-sitemap.js`](https://github.com/every-app/open-seo/blob/main/web/scripts/generate-sitemap.js) and meta tag rendering in [`web/src/lib/seo.ts`](https://github.com/every-app/open-seo/blob/main/web/src/lib/seo.ts). Falls back to `http://localhost:3000` when undefined.

## How Environment Variables Are Loaded

The application uses a generic accessor function defined in [`src/server/lib/runtime-env.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/runtime-env.ts) to safely read `process.env` values:

```typescript
// src/server/lib/runtime-env.ts
export const runtimeEnv = (name: string) =>
  typeof process !== "undefined" ? process.env?.[name] : undefined;

```

This helper prevents undefined errors in edge environments and provides a single injection point for environment reads.

## Configuration Quick Start

Copy the example file and configure for your deployment mode:

```bash

# Copy template

cp .env.example .env

# Example configuration for hosted mode with Google Search Console

cat <<EOF >> .env
DATAFORSEO_API_KEY=sk_test_XXXXXXXXXXXXXXXX
AUTH_MODE=hosted
BETTER_AUTH_SECRET=$(openssl rand -hex 32)
BETTER_AUTH_URL=http://localhost:3001
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
EOF

```

The [`drizzle-prod.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle-prod.config.ts) file demonstrates strict validation for production credentials:

```typescript
// drizzle-prod.config.ts
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  driver: "cloudflare",
  accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
  databaseId: process.env.CLOUDFLARE_DATABASE_ID!,
  token: process.env.CLOUDFLARE_API_TOKEN!,
});

```

For client-side SEO metadata, the application checks multiple variable names:

```typescript
// web/src/lib/seo.ts
import { runtimeEnv } from "~/server/lib/runtime-env";

const siteUrl = runtimeEnv("SITE_URL") ?? runtimeEnv("VITE_SITE_URL") ?? "http://localhost:3000";
export const getFullUrl = (path: string) => 
  `${siteUrl.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;

```

## Summary

- **Minimum requirement**: Only `DATAFORSEO_API_KEY` is mandatory for core functionality.
- **Auth modes**: Cloudflare Access requires `TEAM_DOMAIN` and `POLICY_AUD`; Hosted mode requires `BETTER_AUTH_SECRET` and `BETTER_AUTH_URL`.
- **Production deployment**: Cloudflare Workers needs `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_DATABASE_ID`, and `CLOUDFLARE_API_TOKEN`.
- **Variable access**: All environment reads flow through [`src/server/lib/runtime-env.ts`](https://github.com/every-app/open-seo/blob/main/src/server/lib/runtime-env.ts) using `process.env`.
- **Template reference**: The `.env.example` file contains the authoritative list of all supported variables.

## Frequently Asked Questions

### What is the minimum setup required to run Open-SEO locally?

You only need `DATAFORSEO_API_KEY` set in your `.env` file to fetch SEO data. The application will default to `cloudflare_access` authentication mode (with `AUTH_MODE` unset) and bind to port `3000`, though you will not be able to authenticate users without configuring either Cloudflare Access headers or switching to hosted mode with Better Auth credentials.

### How do I configure Open-SEO for production deployment on Cloudflare Workers?

Set the three Cloudflare-specific variables in your deployment environment: `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_DATABASE_ID`, and `CLOUDFLARE_API_TOKEN`. These are consumed in [`drizzle-prod.config.ts`](https://github.com/every-app/open-seo/blob/main/drizzle-prod.config.ts) to configure the D1 database driver. Missing any of these will cause the deployment to fail immediately due to the non-nullable assertions in the configuration file.

### What authentication options are available and what do they require?

Open-SEO supports three authentication strategies controlled by `AUTH_MODE`. The default `cloudflare_access` mode requires `TEAM_DOMAIN` and `POLICY_AUD` for Cloudflare zero-trust validation. Setting `AUTH_MODE=hosted` switches to Better Auth, requiring `BETTER_AUTH_SECRET` for encryption and `BETTER_AUTH_URL` for callback routing. When `AUTH_MODE` is undefined, the system defaults to Cloudflare Access mode but may lack valid credentials for user identification.

### Are Google Search Console integrations mandatory?

No. Google OAuth is optional and only active when both `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` are provided. These variables are unnecessary unless you specifically want to pull search analytics data from Google's API. Without them, the application continues to function using DataforSEO data exclusively.