PluginInput Breakdown
Understand what your plugin receives: events, logger, config, sessionId, and client.
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(), andoff()
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 messageswarn(message, meta?): Warningserror(message, meta?): Errorsdebug(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.
Related
- Hooks reference: What your plugin can return
- PluginClient reference: Available client methods
- Plugin security model: What plugins can and cannot do
Was this helpful?
Your answer includes the page path and docs version.
