Playwright gives you programmatic control of a real Chromium browser from Node.js. Combined with WA-JS, it becomes the foundation for WhatsApp bots, automated test suites, and data-extraction pipelines — all without modifying WhatsApp’s servers or using unofficial APIs at the network level. WA-JS is injected directly into the browser page, so everyDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/wppconnect-team/wa-js/llms.txt
Use this file to discover all available pages before exploring further.
WPP.* call runs exactly as it does in a regular browser session.
Installation
Installplaywright-chromium for the browser runtime and @wppconnect/wa-js for the injection bundle:
Basic automation script
The following TypeScript example from the WA-JS README shows the complete lifecycle: launch a browser, inject WA-JS, wait for it to be ready, then callWPP functions from Node.js via page.evaluate().
page.evaluate() serialises its return value as JSON across the Node.js/browser boundary. Primitives, plain objects, and arrays work fine. Class instances, functions, and non-serialisable values are not transferred — only their JSON-safe properties come through.How script injection works
page.addScriptTag({ path: require.resolve('@wppconnect/wa-js') }) loads the bundled wppconnect-wa.js file into the page’s JavaScript context. After that call returns, window.WPP exists in the browser, but WA-JS may still be initialising its internal loader. page.waitForFunction(() => window.WPP?.isReady) blocks until the loader has finished patching WhatsApp’s internals and set the isReady flag to true.
Only after that check is it safe to call any WPP.* function.
Passing data between Node.js and the browser
page.evaluate() accepts a serialisable second argument that is passed into the browser-side function:
to and message are declared in Node.js and transferred to the browser context as serialised values. The browser-side arrow function receives them as its parameters. This is the standard pattern for all page.evaluate() calls that need runtime data.
Session persistence
By default,playwright.chromium.launch() creates a temporary browser profile that is discarded when the process exits. That means the next run shows a fresh QR code. To avoid scanning QR on every run, use a persistent context with a fixed user data directory:
userDataDir automatically.
You can also export and import session state as JSON using Playwright’s storageState option, which saves cookies and localStorage but not the full browser profile:
storageState captures cookies and localStorage, but WhatsApp Web also stores cryptographic keys in IndexedDB. A persistent context directory (launchPersistentContext) is more reliable for full session reuse.Running the WA-JS test suite
WA-JS ships a Playwright test suite undertests/. Two entry points are available:
loggedPage fixture from tests/wpp-test.ts. To bootstrap that session for the first time (opens a real browser so you can scan the QR code), run:
wa-js-test-<browser>) and reused automatically by all subsequent npm test runs.
Listening for events
You can register WA-JS event listeners insidepage.evaluate() and bridge them back to Node.js using page.exposeFunction():
page.exposeFunction makes a Node.js callback available as a global function inside the browser, so WA-JS events can trigger Node.js-side processing.