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 naminguserDataDir— persistent browser profile directoryheadless— visible vs background browseruseChrome/executablePath— browser selectionqrTimeout/authTimeout— authentication timingmaxQr— limit QR emission countcacheEnabled— page/runtime memory trade-offlicenseKey— feature unlocks where applicableproxyServerCredentials— outbound proxy supportlinkCode— link-code login flow
Full Configuration Reference
Use the <AutoTypeTable /> to explore all available configuration options directly from the source code.
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:
package.jsonusing thewakeywa.config.jswa.config.cjswa.config.mjswa.config.tswa.config.mtswa.config.ctswa.config.json.warc.warc.jsoncli.config.jslegacy compatibilitycli.config.jsonlegacy compatibility
The first matching file wins. Use --config ./path/to/config when you want to load a specific file instead of relying on discovery.
Config values are merged in this order:
- schema defaults
- config file
WA_*environment variables- CLI flags
- programmatic overrides, mainly for tests and embedding
Arrays are replaced rather than concatenated, so a later plugins value replaces the earlier one.
Config files can export a plain object or a function that returns an object. TypeScript config files are supported by the config loader.
JSON/TS examples
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"
}Use TypeScript or JavaScript when you need environment variables or computed values:
import { defineConfig } from '@open-wa/config';
export default defineConfig({
sessionId: process.env.WA_SESSION_ID ?? 'sales',
port: Number(process.env.WA_PORT ?? 8080),
host: '0.0.0.0',
apiKey: process.env.WA_API_KEY,
userDataDir: process.env.WA_USER_DATA_DIR,
headless: true,
qrTimeout: 0,
authTimeout: 60,
licenseKey: process.env.WA_LICENSE_KEY,
});In v5 config examples, prefer the same WA_* environment names that the config loader reads. If your deployment platform stores secrets under another name, map them into config explicitly instead of assuming bare names such as PORT or API_KEY are runtime config env vars.
Env vars
Runtime config can be supplied with WA_* environment variables. Names are converted from snake case to config keys, so WA_SESSION_ID becomes sessionId, WA_API_KEY becomes apiKey, and WA_QR_TIMEOUT becomes qrTimeout.
Values are coerced where possible:
true,1,yes, andonbecometruefalse,0,no, andoffbecomefalse- numeric strings become numbers for numeric schema fields
- JSON-looking values such as
{...}or[...]are parsed for object and array fields
Common runtime environment variables:
| Environment variable | Config field | Notes |
|---|---|---|
WA_SESSION_ID | sessionId | Stable session name |
WA_PORT | port | Easy API port |
WA_HOST | host | Easy API host |
WA_API_KEY | apiKey | API authentication key |
WA_USER_DATA_DIR | userDataDir | Persistent browser profile directory |
WA_LICENSE_KEY | licenseKey | License key where applicable |
WA_LINK_CODE | linkCode | Phone number for link-code login |
WA_HEADLESS | headless | Browser visibility |
WA_USE_CHROME | useChrome | Prefer local Chrome |
WA_QR_TIMEOUT | qrTimeout | QR wait time |
WA_AUTH_TIMEOUT | authTimeout | Auth wait time |
WA_WEBHOOK | webhook | Webhook target URL |
WA_PLUGINS | plugins | JSON array of plugin refs |
WA_PLUGIN_CONFIG | pluginConfig | JSON 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
--port 8080
--api-key "your-secure-key"
--host "0.0.0.0"
# session identity
--session-id sales
--link-code "447123456789"
# runtime helpers
--pm2
--tunnel
--multi-device
# licensing
--license-key "YOUR-LICENSE-KEY"Full CLI reference
These are the major flags most users need when starting the Easy API from the command line.
| Flag | Maps to | Description |
|---|---|---|
--port 8080, -p 8080 | port | Port for the Easy API server. |
--api-key "key", --key "key", -k "key" | apiKey | Protects API requests. Use this before exposing the API beyond localhost. |
--session-id sales | sessionId | Names the session and keeps auth state separate from other sessions. |
--webhook "https://...", -w "https://..." | webhook | Parsed 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. |
--pm2 | PM2 wrapper | Starts the CLI under PM2 instead of running directly. |
--license-key "key", -l "key" | licenseKey | Supplies a license key for licensed features where applicable. |
--link-code "447123456789" | linkCode | Uses link-code login instead of relying only on QR scanning. |
--tunnel | transitional | Legacy tunnel flag. v5 currently warns that tunnel setup parity is not restored. |
--mcp | future or other-alpha shorthand only | The current source does not parse --mcp. Configure mcp: { enabled: true } in wa.config.* instead, keep apiKey enabled, and use --mcp only if your installed build documents it. |
--host "0.0.0.0", -h "0.0.0.0" | host | Local bind host for the Easy API server. |
Other useful runtime flags include --host, --headless, --headful, --use-chrome, --use-lightpanda, --qr-timeout, --dashboard-port, --no-dashboard, --no-ezqr, --ephemeral, --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 \
--session-id sales \
--port 8080 \
--api-key "$WA_API_KEY" \
--license-key "$WA_LICENSE_KEY" \
--link-code "447123456789"is equivalent to these config fields:
export default {
sessionId: 'sales',
port: 8080,
apiKey: process.env.WA_API_KEY,
licenseKey: process.env.WA_LICENSE_KEY,
linkCode: '447123456789',
};CLI flags win over config-file and environment values. That makes config files good for stable defaults and CLI flags good for one-off local overrides.
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
v5 is still alpha, so a few v4-era flags are present only as transitional compatibility warnings.
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, a relative path, or an absolute path. The module should export a plugin as its default export or as 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, a .env file is convenient, but it should stay in .gitignore. In production, prefer your platform's secret store or a dedicated secret manager. Avoid logging full config objects because nested pluginConfig values often 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 full CLI options table at build time. This new page intentionally documents the commonly used flags first, while the deeper config surface should ultimately stay aligned with the generated reference and runtime schema.

Was this helpful?
Wally and his cute companion coffee mug are coding day and night to keep this up-to-date!
