From ff2e280597ee86fc654c655668962e9b6c1ddff4 Mon Sep 17 00:00:00 2001 From: Adi Aharoni Date: Fri, 20 Mar 2026 19:31:47 +0200 Subject: [PATCH 1/2] feat: support external browser + page in puppeteer options allow passing a pre-existing `browser` and `page` via `options.puppeteer` so the Client can work with a browser you already control. when both are provided, the Client skips puppeteer.launch() and uses them directly. also uses browser.process() in destroy/logout to decide cleanup: close() for launched browsers, disconnect() for connected ones. --- index.d.ts | 7 ++++++- src/Client.js | 27 +++++++++++++++++++-------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/index.d.ts b/index.d.ts index 268d8c38d8..9f44d90d08 100644 --- a/index.d.ts +++ b/index.d.ts @@ -695,7 +695,12 @@ declare namespace WAWebJS { evalOnNewDoc?: Function; /** Puppeteer launch options. View docs here: https://github.com/puppeteer/puppeteer/ */ puppeteer?: puppeteer.PuppeteerNodeLaunchOptions & - puppeteer.ConnectOptions; + puppeteer.ConnectOptions & { + /** Pre-existing browser instance to use instead of launching a new one */ + browser?: puppeteer.Browser; + /** Pre-existing page instance to use */ + page?: puppeteer.Page; + }; /** Determines how to save and restore sessions. Will use LegacySessionAuth if options.session is set. Otherwise, NoAuth will be used. */ authStrategy?: AuthStrategy; /** The version of WhatsApp Web to use. Use options.webVersionCache to configure how the version is retrieved. */ diff --git a/src/Client.js b/src/Client.js index deb4f7edff..e8f7c0849f 100644 --- a/src/Client.js +++ b/src/Client.js @@ -442,7 +442,11 @@ class Client extends EventEmitter { await this.authStrategy.beforeBrowserInitialized(); const puppeteerOpts = this.options.puppeteer; - if ( + if (puppeteerOpts && puppeteerOpts.browser && puppeteerOpts.page) { + // External browser + page provided by caller + browser = puppeteerOpts.browser; + page = puppeteerOpts.page; + } else if ( puppeteerOpts && (puppeteerOpts.browserWSEndpoint || puppeteerOpts.browserURL) ) { @@ -1181,7 +1185,11 @@ class Client extends EventEmitter { const browser = this.pupBrowser; const isConnected = browser?.isConnected?.(); if (isConnected) { - await browser.close(); + if (browser.process()) { + await browser.close(); + } else { + browser.disconnect(); + } } await this.authStrategy.destroy(); } @@ -1193,13 +1201,16 @@ class Client extends EventEmitter { await this.pupPage.evaluate(() => { return window.require('WAWebSocketModel').Socket.logout(); }); - await this.pupBrowser.close(); + if (this.pupBrowser.process()) { + await this.pupBrowser.close(); - let maxDelay = 0; - while (this.pupBrowser.isConnected() && maxDelay < 10) { - // waits a maximum of 1 second before calling the AuthStrategy - await new Promise((resolve) => setTimeout(resolve, 100)); - maxDelay++; + let maxDelay = 0; + while (this.pupBrowser.isConnected() && maxDelay < 10) { + await new Promise((resolve) => setTimeout(resolve, 100)); + maxDelay++; + } + } else { + this.pupBrowser.disconnect(); } await this.authStrategy.logout(); From ed7929f87df79d8ea1c8a37ee790cf9c36100cd4 Mon Sep 17 00:00:00 2001 From: Adi Aharoni Date: Wed, 1 Apr 2026 00:45:58 +0300 Subject: [PATCH 2/2] fix: make page optional when passing external browser create a new page via browser.newPage() when only browser is provided, matching the existing browserWSEndpoint behavior. --- src/Client.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Client.js b/src/Client.js index 64ae8b1ec6..e6a6e38e54 100644 --- a/src/Client.js +++ b/src/Client.js @@ -441,10 +441,10 @@ class Client extends EventEmitter { await this.authStrategy.beforeBrowserInitialized(); const puppeteerOpts = this.options.puppeteer; - if (puppeteerOpts && puppeteerOpts.browser && puppeteerOpts.page) { - // External browser + page provided by caller + if (puppeteerOpts && puppeteerOpts.browser) { + // External browser provided by caller browser = puppeteerOpts.browser; - page = puppeteerOpts.page; + page = puppeteerOpts.page || (await browser.newPage()); } else if ( puppeteerOpts && (puppeteerOpts.browserWSEndpoint || puppeteerOpts.browserURL)