open-wa
DocsPluginInput Breakdown

PluginInput Breakdown

Understand what your plugin receives: events, logger, config, sessionId, and client.

PluginInput Breakdown

The host passes a PluginInput object to your plugin's init() function. It contains the event interface, logger, plugin configuration, session identifier, lifetime signal, and client proxy.

interface PluginInput<TConfig = unknown> {
  events: PluginEventEmitter;
  logger: PluginLogger;
  config: TConfig;
  sessionId: string;
  signal: AbortSignal;
  client: PluginClient;
}

Each field is described below.

events: Filtered Event Emitter

The events field provides on(), once(), and off(). The host gateway checks event metadata and ignores events marked internal or sensitive. It does not create a sandbox around plugin code.

What you can do

  • Subscribe to allowed events with on(), once(), and off()
events.on('message.received', (payload) => {
  logger.info('Message received');
});

What you cannot do

  • Emit through this object: It has no emit() method.
  • Subscribe to metadata marked internal or sensitive: The gateway ignores these requests and logs them. This is based on host event metadata, not name prefixes; unknown names pass to the underlying emitter.

The loader dynamically imports plugins into the host process. They retain that process's Node.js and operating-system permissions, so review plugin source and dependencies before loading them. See the plugin security model for deployment isolation options.

logger: Scoped Logger

The logger provides structured logging with automatic plugin name prefixing.

Methods

logger.info('Plugin initialized', { version: '1.0.0' });
logger.warn('API key is missing, using defaults');
logger.error('Failed to connect', { error: 'ECONNREFUSED' });
logger.debug('Processing message', { messageId: 'abc123' });
  • info(message, meta?): Informational messages
  • warn(message, meta?): Warnings
  • error(message, meta?): Errors
  • debug(message, meta?): Debug output (only visible when debug logging is enabled)

Auto-Prefixing

All log output is automatically prefixed with your plugin name:

[greeting-bot] Plugin initialized { version: '1.0.0' }

Log Persistence

Plugin logs flow through the host's logging system. Whether they are persisted depends on the host's logging configuration. By default, logs are written to stdout/stderr.

config: Validated Configuration

The config field contains your plugin's configuration from wa.config.mjs. When you provide a configSchema, the host validates and parses the value before calling init(); without a schema, it passes the configured value through (or {} when it is absent).

Access Pattern

Your plugin's config is accessed via the pluginConfig key in the global config file:

// wa.config.mjs
export default {
  pluginConfig: {
    'my-plugin': {
      apiUrl: 'https://api.example.com',
      apiKey: process.env.MY_PLUGIN_API_KEY,
    },
  },
};
// src/my-plugin.ts
init: async ({ config }) => {
  // config is { apiUrl: string; apiKey: string }
  // Already validated against your configSchema
  console.log(config.apiUrl);
}

Type Inference

When you provide a configSchema, the config type is automatically inferred:

const configSchema = z.object({
  apiUrl: z.string().url(),
  apiKey: z.string().min(1),
  retries: z.number().int().positive().default(3),
});

// config is typed as { apiUrl: string; apiKey: string; retries: number }
init: async ({ config }) => { ... }

sessionId: Current Session

A string identifier for the current session.

init: async ({ sessionId }) => {
  logger.info('Plugin loaded for session', { sessionId });
}

Use this for:

  • Logging and debugging
  • Scoping data to a specific session
  • Differentiating behavior across multiple sessions

signal: Plugin lifetime

The host aborts this signal when it starts disposing the plugin. Pass it to cancellable work or check signal.aborted before starting another operation.

init: async ({ signal, logger }) => {
  if (signal.aborted) {
    logger.debug('Plugin is already stopping');
  }
  return {};
}

client: WhatsApp Method Proxy

The client is a host-managed proxy for calling methods exposed by window.WAPI in the connected runtime. Its ask() method forwards method names and arguments; the SDK does not apply a safe-method allowlist. The proxy does not restrict Node.js imports or replace process isolation.

init: async ({ client }) => {
  await client.sendText('1234567890@c.us', 'Hello!');
  const number = await client.getHostNumber();
}

See the PluginClient reference for the complete list of available methods.

Was this helpful?

Your answer includes the page path and docs version.

On this page