open-wa
DocsConfiguration and CLI

Configuration and CLI

Core runtime settings for custom code and the most important Easy API CLI flags.

Configuration and CLI

Use this page to choose runtime settings, CLI flags, environment variables, and plugin configuration that match the way you start open-wa.

Common config fields

Use the config object passed to createClient() or exported from wa.config.* for library/runtime behavior such as:

  • sessionId: stable session naming
  • userDataDir: persistent browser profile directory
  • headless: visible vs background browser
  • useChrome / executablePath: browser selection
  • qrTimeout / authTimeout: authentication timing
  • maxQr: limit QR emission count
  • cacheEnabled: page/runtime memory trade-off
  • licenseKey: feature unlocks where applicable
  • proxyServerCredentials: outbound proxy support
  • linkCode: link-code login for embedded createClient applications

Full Configuration Reference

The reference below lists supported configuration fields, types, defaults, and descriptions.

Prop

Type

Example

import { createClient } from '@open-wa/wa-automate';

const client = await createClient({
  sessionId: 'sales',
  useChrome: true,
  headless: true,
  qrTimeout: 0,
  authTimeout: 60,
});

Config file discovery

The CLI loads configuration through the shared config package before applying CLI overrides. By default, discovery starts from the current working directory.

Discovery order is:

  1. The wa key in package.json
  2. wa.config.js
  3. wa.config.cjs
  4. wa.config.mjs
  5. wa.config.ts
  6. wa.config.mts
  7. wa.config.cts
  8. wa.config.json
  9. .warc
  10. .warc.json
  11. cli.config.js legacy compatibility
  12. cli.config.json legacy compatibility

The first matching file wins. Use --config ./path/to/config when you want to load a specific file instead of relying on discovery.

The config loader merges values in this order:

  1. schema defaults
  2. config file
  3. WA_* environment variables
  4. CLI flags
  5. programmatic overrides, mainly for tests and embedding

The config loader replaces arrays instead of concatenating them. A later plugins value replaces the earlier value.

Config files can export a plain object or a function that returns an object. The config loader supports TypeScript config files.

JSON/TS examples

These config fields are available to embedded createClient applications. In the published Easy API CLI 5.1.0, startup applies host: 0.0.0.0 and port: 8002 after config and environment loading, so pass --host and --port explicitly when starting the CLI.

Use JSON when your config is static:

{
  "sessionId": "sales",
  "port": 8080,
  "host": "0.0.0.0",
  "apiKey": "replace-with-env-in-production",
  "headless": true,
  "qrTimeout": 0,
  "authTimeout": 60,
  "licenseKey": "YOUR-LICENSE-KEY"
}

Env vars

Supply runtime config with WA_* environment variables. The loader converts snake-case names to config keys. For example, WA_SESSION_ID becomes sessionId.

The config loader converts values when possible:

  • true, 1, yes, and on become true
  • false, 0, no, and off become false
  • numeric strings become numbers for numeric schema fields
  • the loader parses JSON values such as {...} or [...] for object and array fields

Common runtime environment variables:

Environment variableConfig fieldNotes
WA_SESSION_IDsessionIdStable session name
WA_PORTportThe shared config loader reads this value, but the published CLI 5.1.0 applies port: 8002 after environment variables. Pass --port to choose another port.
WA_HOSThostThe shared config loader reads this value, but the published CLI 5.1.0 applies host: 0.0.0.0 after environment variables. Pass --host to choose another bind address.
WA_API_KEYapiKeyAPI authentication key
WA_USER_DATA_DIRuserDataDirPersistent browser profile directory
WA_LICENSE_KEYlicenseKeyLicense key where applicable
WA_LINK_CODElinkCodeThe shared config loader maps this variable. The published CLI 5.1.0 does not forward the field into startup; pass linkCode explicitly to embedded createClient.
WA_HEADLESSheadlessBrowser visibility
WA_USE_CHROMEuseChromePrefer local Chrome
WA_QR_TIMEOUTqrTimeoutQR wait time
WA_AUTH_TIMEOUTauthTimeoutAuth wait time
WA_WEBHOOKwebhookWebhook target URL
WA_PLUGINSpluginsJSON array of plugin refs
WA_PLUGIN_CONFIGpluginConfigJSON object keyed by plugin name

There are also compatibility aliases for a few browser-related settings, including WA_DEBUG for devtools, WA_BROWSER_WS_ENDPOINT for browserWSEndpoint, WA_BYPASS_CSP for bypassCSP, and WA_USE_LIGHTPANDA for useLightpanda.

High-value CLI flags

# networking (pass explicit values to override published CLI 5.1.0 defaults)
--host "127.0.0.1"
--port 8080
--api-key "your-secure-key"

# session identity
--session-id sales

# runtime helpers
--pm2
--tunnel

# licensing
--license-key "YOUR-LICENSE-KEY"

# isolate explicit chat-triggered code/tool execution
--sandbox-chats
--sandbox-isolation container

Pass linkCode explicitly in an embedded createClient configuration. The shared config loader maps WA_LINK_CODE, but direct createClient calls do not load environment variables automatically. The published Easy API CLI 5.1.0 does not forward link-code settings and has no --link-code flag, so use its QR flow. Select a config file with --config when you need to choose it explicitly. sandboxChats applies only to code or tools explicitly sent through executeInChatSandbox; it does not create a Chromium session per chat or change ordinary message handlers. The boolean form uses the process policy, while the object form controls the isolation boundary and resource access:

export default defineConfig({
  sandboxChats: {
    isolation: 'container', // worker | process | container
    timeoutMs: 30_000,
    idleTimeoutMs: 300_000,
    memoryMb: 256,
    concurrency: 1,
    filesystem: 'none', // none | read-only | workspace
    network: 'none', // none | allowlist
    networkAllowlist: [],
    env: 'none',
    capabilities: ['sendText'],
  },
});

Container mode is the strong boundary for hostile code. Process mode strips ambient globals, environment, and filesystem permission and applies time/memory/output limits, but Node's permission model is defense in depth rather than a complete security boundary. Worker mode is intended for availability isolation around trusted code. Worker and process policies fail closed if they request filesystem, network, or environment access; those host-access policies require container mode.

Full CLI reference

These are the major flags most users need when starting the Easy API from the command line.

FlagMaps toDescription
--port 8080, -p 8080portPort for the Easy API server.
--api-key "key", --key "key", -k "key"apiKeyProtects API requests. Use this before exposing the API beyond localhost.
--session-id salessessionIdNames the session and keeps auth state separate from other sessions.
--webhook "https://...", -w "https://..."webhookParsed as a webhook target URL, but current v5 source warns that CLI webhook registration parity is not restored. Use @open-wa/integration-webhook in plugins plus pluginConfig.webhook for source-backed delivery.
--pm2PM2 wrapperStarts the CLI under PM2 instead of running directly.
--license-key "key", -l "key"licenseKeySupplies a license key for licensed features where applicable.
linkCode in library configlinkCodeEmbedded createClient in 5.1.0 supports link-code login. The published Easy API CLI does not forward this setting and has no --link-code flag.
--tunneltransitionalLegacy tunnel flag. v5 currently warns that tunnel setup parity is not restored.
--mcpunsupported by the current v5 CLIThe parser does not accept this flag. Configure mcp: { enabled: true } in wa.config.*, keep apiKey enabled, and use --config ./wa.config.mjs when selecting that file explicitly.
--host "0.0.0.0", -h "0.0.0.0"hostLocal bind host for the Easy API server.
--sandbox-chatssandboxChats: trueEnables isolated execution for explicit per-chat code/tool calls.
--sandbox-isolation processsandboxChats.isolationSelects worker, process, or container; use container for hostile code.

Other useful runtime flags include --host, --headless, --headful, --use-chrome, --use-lightpanda, --qr-timeout, --dashboard-port, --no-dashboard, --no-ezqr, --ephemeral, --sandbox-chats, --sandbox-isolation, --log-console, --log-level, and --verbose.

The standalone @open-wa/cli entrypoint also accepts output-mode flags such as --interactive, --non-interactive, and --output-mode plain. Those affect terminal output before the runtime config is parsed.

CLI-to-schema mapping

Most CLI flags are thin aliases over config schema fields. For example:

npx @open-wa/wa-automate@5.1.0 \
  --session-id sales \
  --host 127.0.0.1 \
  --port 8080 \
  --api-key "$WA_API_KEY" \
  --license-key "$WA_LICENSE_KEY"

is equivalent to these config fields:

export default {
  sessionId: 'sales',
  port: 8080,
  apiKey: process.env.WA_API_KEY,
  licenseKey: process.env.WA_LICENSE_KEY,
};

Explicit CLI flags win over config-file and environment values. The published CLI 5.1.0 also applies its 0.0.0.0 and 8002 startup defaults after config loading, so always pass --host and --port when those values matter.

Not every flag is a schema field. --config selects which file to load, --pm2 controls process management, and --name controls the PM2 process name.

Deprecated flags

Some v4-era flags remain as compatibility warnings in v5. Replace them with the documented v5 settings below.

When in doubt, prefer the config schema and the flags in this page over older v4 examples.

Plugins field docs

Use plugins to load reusable integrations into the runtime process.

export default {
  plugins: [
    '@open-wa/integration-webhook',
    '@open-wa/integration-chatwoot',
    './plugins/my-local-plugin',
    '/absolute/path/to/plugin.js',
  ],
};

Each item is a plugin reference. It can be an npm package name, a scoped package name, or a file path. The module must export a default plugin or a named plugin export.

Plugins loaded from plugins are imported during createClient() startup. If a plugin does not expose meta.name, it cannot be registered correctly.

PluginConfig docs

Use pluginConfig for plugin-specific settings. The object is keyed by each plugin's meta.name, not necessarily by the package name.

export default {
  plugins: ['@open-wa/integration-webhook', './plugins/moderation'],
  pluginConfig: {
    webhook: {
      url: 'https://your-app.example/webhooks/open-wa',
      headers: {
        'X-Webhook-Secret': process.env.WEBHOOK_SECRET,
      },
    },
    moderation: {
      enabled: true,
      apiKey: process.env.MODERATION_API_KEY,
    },
  },
};

At startup, open-wa looks up pluginConfig[plugin.meta.name]. If the plugin defines a config schema, that value is validated before it is passed to the plugin's init() function.

Example with plugin

import { defineConfig } from '@open-wa/config';

export default defineConfig({
  sessionId: 'support',
  port: 8080,
  host: '0.0.0.0',
  apiKey: process.env.WA_API_KEY,
  webhook: process.env.WA_WEBHOOK,
  plugins: [
    '@open-wa/integration-webhook',
    './plugins/internal-audit-plugin',
  ],
  pluginConfig: {
    webhook: {
      url: process.env.WA_WEBHOOK,
      headers: {
        'X-Webhook-Secret': process.env.WEBHOOK_SECRET,
      },
    },
    'internal-audit': {
      enabled: true,
      logLevel: 'info',
    },
  },
});

Secret management

Keep secrets out of committed config files. Use environment variables for apiKey, licenseKey, webhook secrets, Chatwoot tokens, and plugin API keys.

For local development, keep the .env file in .gitignore. In production, use the platform secret store or a secret manager. Do not log complete config objects. Nested pluginConfig values frequently contain tokens.

Session events worth knowing about

If you need QR images, session-data capture, or low-level launch state, read Session events.

One important caveat

The old Docusaurus site generated a complete CLI options table at build time. This page gives the common flags first. The detailed config surface must agree with the generated reference and runtime schema.

Was this helpful?

Your answer includes the page path and docs version.

On this page