{"id":13588664,"url":"https://github.com/apify/browser-pool","last_synced_at":"2025-11-03T16:28:13.351Z","repository":{"id":37627173,"uuid":"304949179","full_name":"apify/browser-pool","owner":"apify","description":"A Node.js library to easily manage and rotate a pool of web browsers, using any of the popular browser automation libraries like Puppeteer, Playwright, or SecretAgent.","archived":false,"fork":false,"pushed_at":"2022-11-14T13:39:06.000Z","size":250,"stargazers_count":94,"open_issues_count":7,"forks_count":15,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-09T15:04:39.545Z","etag":null,"topics":["browser-automation","headless-browsers","playwright","puppeteer","rpa","scraping","web-scraping"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apify.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-10-17T19:01:33.000Z","updated_at":"2025-02-18T02:55:27.000Z","dependencies_parsed_at":"2023-01-21T11:46:53.399Z","dependency_job_id":null,"html_url":"https://github.com/apify/browser-pool","commit_stats":null,"previous_names":[],"tags_count":72,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apify%2Fbrowser-pool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apify%2Fbrowser-pool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apify%2Fbrowser-pool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apify%2Fbrowser-pool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apify","download_url":"https://codeload.github.com/apify/browser-pool/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248055284,"owners_count":21040157,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser-automation","headless-browsers","playwright","puppeteer","rpa","scraping","web-scraping"],"created_at":"2024-08-01T15:06:51.175Z","updated_at":"2025-11-03T16:28:13.323Z","avatar_url":"https://github.com/apify.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# (DEPRECATED) Browser Pool - the headless browser manager\n\n\u003e **DEPRECATED!** \n\u003e\n\u003e The Browser Pool package now lives in the [`crawlee`](https://github.com/apify/crawlee) repository - submit all your issues and PRs there. This repository is no longer actively maintained!\n\nBrowser Pool is a small, but powerful and extensible library, that allows you to seamlessly\ncontrol multiple headless browsers at the same time with only a little configuration, and a\nsingle function call. Currently it supports [Puppeteer](https://github.com/puppeteer/puppeteer),\n[Playwright](https://github.com/microsoft/playwright) and it can be easily extended with plugins.\n\nWe created Browser Pool because we regularly needed to execute tasks concurrently in many\nheadless browsers and their pages, but we did not want to worry about launching browsers, closing\nbrowsers, restarting them after crashes and so on. We also wanted to easily and reliably manage\nthe whole browser / page lifecycle.\n\nYou can use Browser Pool for scraping the internet at scale, testing your website\nin multiple browsers at the same time or launching web automation robots. We're interested\nto hear about your use cases in the [Discussions](https://github.com/apify/browser-pool/discussions).\n\n\u003c!-- toc --\u003e\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Launching multiple browsers](#launching-multiple-browsers)\n- [Features](#features)\n  * [Simple configuration](#simple-configuration)\n  * [Proxy management](#proxy-management)\n  * [Lifecycle management with hooks](#lifecycle-management-with-hooks)\n  * [Manipulating playwright context using `pageOptions` or `launchOptions`](#manipulating-playwright-context-using-pageoptions-or-launchoptions)\n  * [Single API for common operations](#single-api-for-common-operations)\n  * [Graceful browser closing](#graceful-browser-closing)\n  * [Changing browser fingerprints a.k.a. browser signatures](#changing-browser-fingerprints-aka-browser-signatures)\n  * [(UNSTABLE) Extensibility with plugins](#unstable-extensibility-with-plugins)\n- [API Reference](#api-reference)\n\n\u003c!-- tocstop --\u003e\n\n## Installation\nUse NPM or Yarn to install `browser-pool`. Note that `browser-pool` does not come preinstalled\nwith browser automation libraries. This allows you to choose your own libraries and their\nversions and it also makes `browser-pool` much smaller.\n\nRun this command to install `browser-pool` and the `playwright` browser automation library.\n```bash\nnpm install browser-pool playwright\n```\n\n## Usage\nThis simple example shows how to open a page in a browser using Browser Pool.\nWe use the provided `PlaywrightPlugin` to wrap a Playwright installation of\nyour own. By calling `browserPool.newPage()` you launch a new Firefox browser\nand open a new page in that browser.\n\n```js\nconst { BrowserPool, PlaywrightPlugin } = require('browser-pool');\nconst playwright = require('playwright');\n\nconst browserPool = new BrowserPool({\n    browserPlugins: [new PlaywrightPlugin(playwright.chromium)],\n});\n\n// An asynchronous IIFE (immediately invoked function expression)\n// allows us to use the 'await' keyword.\n(async () =\u003e {\n    // Launches Chromium with Playwright and returns a Playwright Page.\n    const page1 = await browserPool.newPage();\n    // You can interact with the page as you're used to.\n    await page1.goto('https://example.com');\n    // When you're done, close the page.\n    await page1.close();\n\n    // Opens a second page in the same browser.\n    const page2 = await browserPool.newPage();\n    // When everything's finished, tear down the pool.\n    await browserPool.destroy();\n})();\n```\n\n\u003e Browser Pool uses the same asynchronous API as the underlying automation libraries which means\nextensive use of Promises and the `async` / `await` pattern. [Visit MDN to learn more](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await).\n\n## Launching multiple browsers\nThe basic example shows how to launch a single browser, but the purpose\nof Browser Pool is to launch many browsers. This is done automatically\nin the background. You only need to provide the relevant plugins and call\n`browserPool.newPage()`.\n\n```js\nconst { BrowserPool, PlaywrightPlugin } = require('browser-pool');\nconst playwright = require('playwright');\n\nconst browserPool = new BrowserPool({\n    browserPlugins: [\n        new PlaywrightPlugin(playwright.chromium),\n        new PlaywrightPlugin(playwright.firefox),\n        new PlaywrightPlugin(playwright.webkit),\n    ],\n});\n\n(async () =\u003e {\n    // Open 4 pages in 3 browsers. The browsers are launched\n    // in a round-robin fashion based on the plugin order.\n    const chromiumPage = await browserPool.newPage();\n    const firefoxPage = await browserPool.newPage();\n    const webkitPage = await browserPool.newPage();\n    const chromiumPage2 = await browserPool.newPage();\n\n    // Don't forget to close pages / destroy pool when you're done.\n})();\n```\n\nThis round-robin way of opening pages may not be useful for you,\nif you need to consistently run tasks in multiple environments.\nFor that, there's the `newPageWithEachPlugin` function.\n\n```js\nconst { BrowserPool, PlaywrightPlugin, PuppeteerPlugin } = require('browser-pool');\nconst playwright = require('playwright');\nconst puppeteer = require('puppeteer');\n\nconst browserPool = new BrowserPool({\n    browserPlugins: [\n        new PlaywrightPlugin(playwright.chromium),\n        new PuppeteerPlugin(puppeteer),\n    ],\n});\n\n(async () =\u003e {\n    const pages = await browserPool.newPageWithEachPlugin();\n    const promises = pages.map(async page =\u003e {\n        // Run some task with each page\n        // pages are in order of plugins:\n        // [playwrightPage, puppeteerPage]\n        await page.close();\n    });\n    await Promise.all(promises);\n\n    // Continue with some more work.\n})();\n```\n\n## Features\nBesides a simple interface for launching browsers, Browser Pool includes\nother helpful features that make browser management more convenient.\n\n### Simple configuration\nYou can easily set the maximum number of pages that can be open in a given\nbrowser and also the maximum number of pages to process before a browser\n[is retired](#graceful-browser-closing).\n\n```js\nconst browserPool = new BrowserPool({\n    maxOpenPagesPerBrowser: 20,\n    retireBrowserAfterPageCount: 100,\n});\n```\n\nYou can configure the browser launch options either right in the plugins:\n\n```js\nconst playwrightPlugin = new PlaywrightPlugin(playwright.chromium, {\n    launchOptions: {\n        headless: true,\n    }\n})\n```\n\nOr dynamically in [pre-launch hooks](#lifecycle-management-with-hooks):\n\n```js\nconst browserPool = new BrowserPool({\n    preLaunchHooks: [(pageId, launchContext) =\u003e {\n        if (pageId === 'headful') {\n            launchContext.launchOptions.headless = false;\n        }\n    }]\n});\n```\n\n### Proxy management\nWhen scraping at scale or testing websites from multiple geolocations,\none often needs to use proxy servers. Setting up an authenticated proxy\nin Puppeteer can be cumbersome, so we created a helper that does all\nthe heavy lifting for you. Simply provide a proxy URL with authentication\ncredentials, and you're done. It works the same for Playwright too.\n\n```js\nconst puppeteerPlugin = new PuppeteerPlugin(puppeteer, {\n    proxyUrl: 'http://\u003cusername\u003e:\u003cpassword\u003e@proxy.com:8000'\n});\n```\n\n\u003e We plan to extend this by adding a proxy-per-page functionality,\n\u003e allowing you to rotate proxies per page, rather than per browser.\n\n### Lifecycle management with hooks\nBrowser Pool allows you to manage the full browser / page lifecycle\nby attaching hooks to the most important events. Asynchronous hooks\nare supported, and their execution order is guaranteed.\n\nThe first parameter of each hook is either a `pageId` for the hooks\nexecuted before a `page` is created or a `page` afterwards. This is\nuseful to keep track of which hook was triggered by which `newPage()`\ncall.\n\n```js\nconst browserPool = new BrowserPool({\n    browserPlugins: [\n        new PlaywrightPlugin(playwright.chromium),\n    ],\n    preLaunchHooks: [(pageId, launchContext) =\u003e {\n        // You can use pre-launch hooks to make dynamic changes\n        // to the launchContext, such as changing a proxyUrl\n        // or updating the browser launchOptions\n\n        pageId === 'my-page' // true\n    }],\n    postPageCreateHooks: [(page, browserController) =\u003e {\n        // It makes sense to make global changes to pages\n        // in post-page-create hooks. For example, you can\n        // inject some JavaScript library, such as jQuery.\n\n        browserPool.getPageId(page) === 'my-page' // true\n    }]\n});\n\nawait browserPool.newPage({ id: 'my-page' });\n```\n\n\u003e See the API Documentation for all hooks and their arguments.\n### Manipulating playwright context using `pageOptions` or `launchOptions`\nPlaywright allows customizing multiple browser attributes by browser context.\nYou can customize some of them once the context is created, but some need to be customized within its creation.\nThis part of the documentation should explain how you can effectively customize the browser context.\n\nFirst of all, let's take a look at what kind of context strategy you chose. You can choose between two strategies by `useIncognitoPages` `LaunchContext` option.\n\nSuppose you decide to keep `useIncognitoPages` default `false` and create a shared context across all pages launched by one browser. In this case,  you should pass the `contextOptions` as a `launchOptions` since the context is created within the new browser launch. The `launchOptions` corresponds to these [playwright options](https://playwright.dev/docs/api/class-browsertype#browsertypelaunchpersistentcontextuserdatadir-options). As you can see, these options contain not only ordinary playwright launch options but also the context options.\n\nIf you set `useIncognitoPages` to `true`, you will create a new context within each new page, which allows you to handle each page its cookies and application data. This approach allows you to pass the context options as `pageOptions` because a new context is created once you create a new page. In this case, the `pageOptions` corresponds to these [playwright options](https://playwright.dev/docs/api/class-browser#browsernewpageoptions).\n\n**Changing context options with `LaunchContext`:**\n\nThis will only work if you keep the default value for `useIncognitoPages` (`false`).\n```javascript\nconst browserPool = new BrowserPool({\n    browserPlugins: [\n        new PlaywrightPlugin(\n            playwright.chromium,\n            {\n                launchOptions: {\n                    deviceScaleFactor: 2,\n                },\n            },\n        ),\n    ],\n\n});\n```\n**Changing context options with `browserPool.newPage` options:**\n\n```javascript\nconst browserPool = new BrowserPool({\n     browserPlugins: [\n        new PlaywrightPlugin(\n            playwright.chromium,\n            {\n                useIncognitoPages: true, // You must turn on incognito pages.\n                launchOptions: {\n                    // launch options\n                    headless: false,\n                    devtools: true,\n                },\n            },\n        ),\n    ],\n});\n\n(async () =\u003e {\n    // Launches Chromium with Playwright and returns a Playwright Page.\n    const page = await browserPool.newPage({\n        pageOptions: {\n            // context options\n            deviceScaleFactor: 2,\n            colorScheme: 'light',\n            locale: 'de-DE',\n        },\n    });\n})();\n\n```\n**Changing context options with `prePageCreateHooks` options:**\n```javascript\nconst browserPool = new BrowserPool({\n    browserPlugins: [\n        new PlaywrightPlugin(\n            playwright.chromium,\n            {\n                useIncognitoPages: true,\n                launchOptions: {\n                // launch options\n                    headless: false,\n                    devtools: true,\n                },\n            },\n        ),\n    ],\n    prePageCreateHooks: [\n        (pageId, browserController, pageOptions) =\u003e {\n            pageOptions.deviceScaleFactor = 2;\n            pageOptions.colorScheme = 'dark';\n            pageOptions.locale = 'de-DE';\n\n            // You must modify the 'pageOptions' object, not assign to the variable.\n            // pageOptions = {deviceScaleFactor: 2, ...etc} =\u003e This will not work!\n        },\n    ],\n});\n\n(async () =\u003e {\n    // Launches Chromium with Playwright and returns a Playwright Page.\n    const page = await browserPool.newPage();\n})();\n```\n### Single API for common operations\nPuppeteer and Playwright handle some things differently. Browser Pool\nattempts to remove those differences for the most common use-cases.\n\n```js\n// Playwright\nconst cookies = await context.cookies();\nawait context.addCookies(cookies);\n\n// Puppeteer\nconst cookies = await page.cookies();\nawait page.setCookie(...cookies);\n\n// BrowserPool uses the same API for all plugins\nconst cookies = await browserController.getCookies(page);\nawait browserController.setCookies(page, cookies);\n```\n\n### Graceful browser closing\nWith Browser Pool, browsers are not closed, but retired. A retired browser\nwill no longer open new pages, but it will wait until the open pages are closed,\nallowing your running tasks to finish. If a browser gets stuck in limbo,\nit will be killed after a timeout to prevent hanging browser processes.\n\n### Changing browser fingerprints a.k.a. browser signatures\nChanging browser fingerprints is beneficial for avoiding getting blocked and simulating real user browsers.\nWith Browser Pool, you can do this otherwise complicated technique by enabling the `useFingerprints` option.\nThe fingerprints are by default tied to the respective session (and proxy URLs) to not use the same unique fingerprint from various IP addresses.\nYou can disable this behavior in the [`fingerprintOptions`](#new_BrowserPool_new). Using `fingerprintsOptions`, you can also control which fingerprints are generated.\nYou can control parameters as browser, operating system, and browser versions.\n\n### (UNSTABLE) Extensibility with plugins\nA new super cool browser automation library appears? No problem, we add\na simple plugin to Browser Pool and it automagically works.\n\n\u003e The BrowserPlugin and BrowserController interfaces are unstable and may\n\u003e change if we find some implementation to be sub-optimal.\n\n## API Reference\nAll public classes, methods and their parameters can be inspected in this API reference.\n\n\u003ca name=\"module_browser-pool\"\u003e\u003c/a\u003e\n\n### browser-pool\nThe `browser-pool` module exports three constructors. One for `BrowserPool`\nitself and two for the included Puppeteer and Playwright plugins.\n\n**Example:**\n```js\nconst {\n BrowserPool,\n PuppeteerPlugin,\n PlaywrightPlugin\n} = require('browser-pool');\nconst puppeteer = require('puppeteer');\nconst playwright = require('playwright');\n\nconst browserPool = new BrowserPool({\n    browserPlugins: [\n        new PuppeteerPlugin(puppeteer),\n        new PlaywrightPlugin(playwright.chromium),\n    ]\n});\n```\n\n**Properties**\n\n| Name | Type |\n| --- | --- |\n| BrowserPool | [\u003ccode\u003eBrowserPool\u003c/code\u003e](#BrowserPool) | \n| PuppeteerPlugin | \u003ccode\u003ePuppeteerPlugin\u003c/code\u003e | \n| PlaywrightPlugin | \u003ccode\u003ePlaywrightPlugin\u003c/code\u003e | \n\n\n* * *\n\n\u003ca name=\"BrowserPool\"\u003e\u003c/a\u003e\n\n### BrowserPool\nThe `BrowserPool` class is the most important class of the `browser-pool` module.\nIt manages opening and closing of browsers and their pages and its constructor\noptions allow easy configuration of the browsers' and pages' lifecycle.\n\nThe most important and useful constructor options are the various lifecycle hooks.\nThose allow you to sequentially call a list of (asynchronous) functions at each\nstage of the browser / page lifecycle.\n\n**Example:**\n```js\nconst { BrowserPool, PlaywrightPlugin } = require('browser-pool');\nconst playwright = require('playwright');\n\nconst browserPool = new BrowserPool({\n    browserPlugins: [ new PlaywrightPlugin(playwright.chromium)],\n    preLaunchHooks: [(pageId, launchContext) =\u003e {\n        // do something before a browser gets launched\n        launchContext.launchOptions.headless = false;\n    }],\n    postLaunchHooks: [(pageId, browserController) =\u003e {\n        // manipulate the browser right after launch\n        console.dir(browserController.browser.contexts());\n    }],\n    prePageCreateHooks: [(pageId, browserController) =\u003e {\n        if (pageId === 'my-page') {\n            // make changes right before a specific page is created\n        }\n    }],\n    postPageCreateHooks: [async (page, browserController) =\u003e {\n        // update some or all new pages\n        await page.evaluate(() =\u003e {\n            // now all pages will have 'foo'\n            window.foo = 'bar'\n        })\n    }],\n    prePageCloseHooks: [async (page, browserController) =\u003e {\n        // collect information just before a page closes\n        await page.screenshot();\n    }],\n    postPageCloseHooks: [(pageId, browserController) =\u003e {\n        // clean up or log after a job is done\n        console.log('Page closed: ', pageId)\n    }]\n});\n```\n\n\n* [BrowserPool](#BrowserPool)\n    * [`new BrowserPool(options)`](#new_BrowserPool_new)\n    * [`.newPage(options)`](#BrowserPool+newPage) ⇒ \u003ccode\u003ePromise.\u0026lt;Page\u0026gt;\u003c/code\u003e\n    * [`.newPageInNewBrowser(options)`](#BrowserPool+newPageInNewBrowser) ⇒ \u003ccode\u003ePromise.\u0026lt;Page\u0026gt;\u003c/code\u003e\n    * [`.newPageWithEachPlugin(optionsList)`](#BrowserPool+newPageWithEachPlugin) ⇒ \u003ccode\u003ePromise.\u0026lt;Array.\u0026lt;Page\u0026gt;\u0026gt;\u003c/code\u003e\n    * [`.getBrowserControllerByPage(page)`](#BrowserPool+getBrowserControllerByPage) ⇒ [\u003ccode\u003eBrowserController\u003c/code\u003e](#BrowserController)\n    * [`.getPage(id)`](#BrowserPool+getPage) ⇒ \u003ccode\u003ePage\u003c/code\u003e\n    * [`.getPageId(page)`](#BrowserPool+getPageId) ⇒ \u003ccode\u003estring\u003c/code\u003e\n    * [`.retireBrowserController(browserController)`](#BrowserPool+retireBrowserController)\n    * [`.retireBrowserByPage(page)`](#BrowserPool+retireBrowserByPage)\n    * [`.retireAllBrowsers()`](#BrowserPool+retireAllBrowsers)\n    * [`.closeAllBrowsers()`](#BrowserPool+closeAllBrowsers) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n    * [`.destroy()`](#BrowserPool+destroy) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n\n\n* * *\n\n\u003ca name=\"new_BrowserPool_new\"\u003e\u003c/a\u003e\n\n#### `new BrowserPool(options)`\n\n| Param | Type | Default | Description |\n| --- | --- | --- | --- |\n| options | \u003ccode\u003eobject\u003c/code\u003e |  |  |\n| options.browserPlugins | [\u003ccode\u003eArray.\u0026lt;BrowserPlugin\u0026gt;\u003c/code\u003e](#BrowserPlugin) |  | Browser plugins are wrappers of browser automation libraries that  allow `BrowserPool` to control browsers with those libraries.  `browser-pool` comes with a `PuppeteerPlugin` and a `PlaywrightPlugin`. |\n| [options.maxOpenPagesPerBrowser] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e20\u003c/code\u003e | Sets the maximum number of pages that can be open in a browser at the  same time. Once reached, a new browser will be launched to handle the excess. |\n| [options.retireBrowserAfterPageCount] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e100\u003c/code\u003e | Browsers tend to get bloated after processing a lot of pages. This option  configures the number of processed pages after which the browser will  automatically retire and close. A new browser will launch in its place. |\n| [options.operationTimeoutSecs] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e15\u003c/code\u003e | As we know from experience, async operations of the underlying libraries,  such as launching a browser or opening a new page, can get stuck.  To prevent `BrowserPool` from getting stuck, we add a timeout  to those operations and you can configure it with this option. |\n| [options.closeInactiveBrowserAfterSecs] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e300\u003c/code\u003e | Browsers normally close immediately after their last page is processed.  However, there could be situations where this does not happen. Browser Pool  makes sure all inactive browsers are closed regularly, to free resources. |\n| [options.preLaunchHooks] | \u003ccode\u003eArray.\u0026lt;function()\u0026gt;\u003c/code\u003e |  | Pre-launch hooks are executed just before a browser is launched and provide  a good opportunity to dynamically change the launch options.  The hooks are called with two arguments:  `pageId`: `string` and `launchContext`: [LaunchContext](#LaunchContext) |\n| [options.postLaunchHooks] | \u003ccode\u003eArray.\u0026lt;function()\u0026gt;\u003c/code\u003e |  | Post-launch hooks are executed as soon as a browser is launched.  The hooks are called with two arguments:  `pageId`: `string` and `browserController`: [BrowserController](#BrowserController)  To guarantee order of execution before other hooks in the same browser,  the [BrowserController](#BrowserController) methods cannot be used until the post-launch  hooks complete. If you attempt to call `await browserController.close()` from  a post-launch hook, it will deadlock the process. This API is subject to change. |\n| [options.prePageCreateHooks] | \u003ccode\u003eArray.\u0026lt;function()\u0026gt;\u003c/code\u003e |  | Pre-page-create hooks are executed just before a new page is created. They  are useful to make dynamic changes to the browser before opening a page.  The hooks are called with two arguments:  `pageId`: `string`, `browserController`: [BrowserController](#BrowserController) and  `pageOptions`: `object|undefined` - This only works if the underlying `BrowserController` supports new page options.  So far, new page options are only supported by `PlaywrightController`.  If the page options are not supported by `BrowserController` the `pageOptions` argument is `undefined`. |\n| [options.postPageCreateHooks] | \u003ccode\u003eArray.\u0026lt;function()\u0026gt;\u003c/code\u003e |  | Post-page-create hooks are called right after a new page is created  and all internal actions of Browser Pool are completed. This is the  place to make changes to a page that you would like to apply to all  pages. Such as injecting a JavaScript library into all pages.  The hooks are called with two arguments:  `page`: `Page` and `browserController`: [BrowserController](#BrowserController) |\n| [options.prePageCloseHooks] | \u003ccode\u003eArray.\u0026lt;function()\u0026gt;\u003c/code\u003e |  | Pre-page-close hooks give you the opportunity to make last second changes  in a page that's about to be closed, such as saving a snapshot or updating  state.  The hooks are called with two arguments:  `page`: `Page` and `browserController`: [BrowserController](#BrowserController) |\n| [options.postPageCloseHooks] | \u003ccode\u003eArray.\u0026lt;function()\u0026gt;\u003c/code\u003e |  | Post-page-close hooks allow you to do page related clean up.  The hooks are called with two arguments:  `pageId`: `string` and `browserController`: [BrowserController](#BrowserController) |\n|[options.useFingerprints] | \u003ccode\u003eboolean\u003c/code\u003e | \u003ccode\u003efalse\u003c/code\u003e | If true the Browser pool will automatically generate and inject fingerprints to browsers.|\n| [options.fingerprintsOptions] | \u003ccode\u003eFingerprintOptions \u003c/code\u003e | | Fingerprints options that allows customizing the fingerprinting behavior. |\n| [options.fingerprintsOptions.fingerprintGeneratorOptions] | | | See the [Fingerprint generator](\"https://github.com/apify/fingerprint-generator#headergeneratoroptions\") documentation. |\n| [options.fingerprintsOptions.useFingerprintPerProxyCache] | \u003ccode\u003eboolean\u003c/code\u003e | \u003ccode\u003etrue\u003c/code\u003e| Fingerprints are autimatically assigned to an IP address so 1 IP equals 1 fingerprint. You can disable this behavior by settings this property to false. |\n| [options.fingerprintsOptions.fingerprintPerProxyCacheSize] | \u003ccode\u003enumber\u003c/code\u003e | \u003ccode\u003e10000\u003c/code\u003e | Maximum number of IP to fingerprint pairs.\n\n\n\n* * *\n\n\u003ca name=\"BrowserPool+newPage\"\u003e\u003c/a\u003e\n\n#### `browserPool.newPage(options)` ⇒ \u003ccode\u003ePromise.\u0026lt;Page\u0026gt;\u003c/code\u003e\nOpens a new page in one of the running browsers or launches\na new browser and opens a page there, if no browsers are active,\nor their page limits have been exceeded.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| options | \u003ccode\u003eobject\u003c/code\u003e |  |\n| [options.id] | \u003ccode\u003estring\u003c/code\u003e | Assign a custom ID to the page. If you don't a random string ID  will be generated. |\n| [options.pageOptions] | \u003ccode\u003eobject\u003c/code\u003e | Some libraries (Playwright) allow you to open new pages with specific  options. Use this property to set those options. |\n| [options.browserPlugin] | [\u003ccode\u003eBrowserPlugin\u003c/code\u003e](#BrowserPlugin) | Choose a plugin to open the page with. If none is provided,  one of the pool's available plugins will be used.  It must be one of the plugins browser pool was created with.  If you wish to start a browser with a different configuration,  see the `newPageInNewBrowser` function. |\n\n\n* * *\n\n\u003ca name=\"BrowserPool+newPageInNewBrowser\"\u003e\u003c/a\u003e\n\n#### `browserPool.newPageInNewBrowser(options)` ⇒ \u003ccode\u003ePromise.\u0026lt;Page\u0026gt;\u003c/code\u003e\nUnlike [newPage](newPage), `newPageInNewBrowser` always launches a new\nbrowser to open the page in. Use the `launchOptions` option to\nconfigure the new browser.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| options | \u003ccode\u003eobject\u003c/code\u003e |  |\n| [options.id] | \u003ccode\u003estring\u003c/code\u003e | Assign a custom ID to the page. If you don't a random string ID  will be generated. |\n| [options.pageOptions] | \u003ccode\u003eobject\u003c/code\u003e | Some libraries (Playwright) allow you to open new pages with specific  options. Use this property to set those options. |\n| [options.launchOptions] | \u003ccode\u003eobject\u003c/code\u003e | Options that will be used to launch the new browser. |\n| [options.browserPlugin] | [\u003ccode\u003eBrowserPlugin\u003c/code\u003e](#BrowserPlugin) | Provide a plugin to launch the browser. If none is provided,  one of the pool's available plugins will be used.  If you configured `BrowserPool` to rotate multiple libraries,  such as both Puppeteer and Playwright, you should always set  the `browserPlugin` when using the `launchOptions` option.  The plugin will not be added to the list of plugins used by  the pool. You can either use one of those, to launch a specific  browser, or provide a completely new configuration. |\n\n\n* * *\n\n\u003ca name=\"BrowserPool+newPageWithEachPlugin\"\u003e\u003c/a\u003e\n\n#### `browserPool.newPageWithEachPlugin(optionsList)` ⇒ \u003ccode\u003ePromise.\u0026lt;Array.\u0026lt;Page\u0026gt;\u0026gt;\u003c/code\u003e\nOpens new pages with all available plugins and returns an array\nof pages in the same order as the plugins were provided to `BrowserPool`.\nThis is useful when you want to run a script in multiple environments\nat the same time, typically in testing or website analysis.\n\n**Example:**\n```js\nconst browserPool = new BrowserPool({\n    browserPlugins: [\n        new PlaywrightPlugin(playwright.chromium),\n        new PlaywrightPlugin(playwright.firefox),\n        new PlaywrightPlugin(playwright.webkit),\n        new PuppeteerPlugin(puppeteer),\n    ]\n});\n\nconst pages = await browserPool.newPageWithEachPlugin();\nconst [chromiumPage, firefoxPage, webkitPage, puppeteerPage] = pages;\n```\n\n\n| Param | Type |\n| --- | --- |\n| optionsList | \u003ccode\u003eArray.\u0026lt;object\u0026gt;\u003c/code\u003e | \n\n\n* * *\n\n\u003ca name=\"BrowserPool+getBrowserControllerByPage\"\u003e\u003c/a\u003e\n\n#### `browserPool.getBrowserControllerByPage(page)` ⇒ [\u003ccode\u003eBrowserController\u003c/code\u003e](#BrowserController)\nRetrieves a [BrowserController](#BrowserController) for a given page. This is useful\nwhen you're working only with pages and need to access the browser\nmanipulation functionality.\n\nYou could access the browser directly from the page,\nbut that would circumvent `BrowserPool` and most likely\ncause weird things to happen, so please always use `BrowserController`\nto control your browsers. The function returns `undefined` if the\nbrowser is closed.\n\n\n| Param | Type | Description |\n| --- | --- | --- |\n| page | \u003ccode\u003ePage\u003c/code\u003e | Browser plugin page |\n\n\n* * *\n\n\u003ca name=\"BrowserPool+getPage\"\u003e\u003c/a\u003e\n\n#### `browserPool.getPage(id)` ⇒ \u003ccode\u003ePage\u003c/code\u003e\nIf you provided a custom ID to one of your pages or saved the\nrandomly generated one, you can use this function to retrieve\nthe page. If the page is no longer open, the function will\nreturn `undefined`.\n\n\n| Param | Type |\n| --- | --- |\n| id | \u003ccode\u003estring\u003c/code\u003e | \n\n\n* * *\n\n\u003ca name=\"BrowserPool+getPageId\"\u003e\u003c/a\u003e\n\n#### `browserPool.getPageId(page)` ⇒ \u003ccode\u003estring\u003c/code\u003e\nPage IDs are used throughout `BrowserPool` as a method of linking\nevents. You can use a page ID to track the full lifecycle of the page.\nIt is created even before a browser is launched and stays with the page\nuntil it's closed.\n\n\n| Param | Type |\n| --- | --- |\n| page | \u003ccode\u003ePage\u003c/code\u003e | \n\n\n* * *\n\n\u003ca name=\"BrowserPool+retireBrowserController\"\u003e\u003c/a\u003e\n\n#### `browserPool.retireBrowserController(browserController)`\nRemoves a browser controller from the pool. The underlying\nbrowser will be closed after all its pages are closed.\n\n\n| Param | Type |\n| --- | --- |\n| browserController | [\u003ccode\u003eBrowserController\u003c/code\u003e](#BrowserController) | \n\n\n* * *\n\n\u003ca name=\"BrowserPool+retireBrowserByPage\"\u003e\u003c/a\u003e\n\n#### `browserPool.retireBrowserByPage(page)`\nRemoves a browser from the pool. It will be\nclosed after all its pages are closed.\n\n\n| Param | Type |\n| --- | --- |\n| page | \u003ccode\u003ePage\u003c/code\u003e | \n\n\n* * *\n\n\u003ca name=\"BrowserPool+retireAllBrowsers\"\u003e\u003c/a\u003e\n\n#### `browserPool.retireAllBrowsers()`\nRemoves all active browsers from the pool. The browsers will be\nclosed after all their pages are closed.\n\n\n* * *\n\n\u003ca name=\"BrowserPool+closeAllBrowsers\"\u003e\u003c/a\u003e\n\n#### `browserPool.closeAllBrowsers()` ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\nCloses all managed browsers without waiting for pages to close.\n\n\n* * *\n\n\u003ca name=\"BrowserPool+destroy\"\u003e\u003c/a\u003e\n\n#### `browserPool.destroy()` ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\nCloses all managed browsers and tears down the pool.\n\n\n* * *\n\n\u003ca name=\"BrowserController\"\u003e\u003c/a\u003e\n\n### BrowserController\nThe `BrowserController` serves two purposes. First, it is the base class that\nspecialized controllers like `PuppeteerController` or `PlaywrightController`\nextend. Second, it defines the public interface of the specialized classes\nwhich provide only private methods. Therefore, we do not keep documentation\nfor the specialized classes, because it's the same for all of them.\n\n**Properties**\n\n| Name | Type | Description |\n| --- | --- | --- |\n| id | \u003ccode\u003estring\u003c/code\u003e |  |\n| browserPlugin | [\u003ccode\u003eBrowserPlugin\u003c/code\u003e](#BrowserPlugin) | The `BrowserPlugin` instance used to launch the browser. |\n| browser | \u003ccode\u003eBrowser\u003c/code\u003e | Browser representation of the underlying automation library. |\n| launchContext | [\u003ccode\u003eLaunchContext\u003c/code\u003e](#LaunchContext) | The configuration the browser was launched with. |\n\n\n* [BrowserController](#BrowserController)\n    * [`.close()`](#BrowserController+close) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n    * [`.kill()`](#BrowserController+kill) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n    * [`.setCookies(page, cookies)`](#BrowserController+setCookies) ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n    * [`.getCookies(page)`](#BrowserController+getCookies) ⇒ \u003ccode\u003ePromise.\u0026lt;Array.\u0026lt;object\u0026gt;\u0026gt;\u003c/code\u003e\n\n\n* * *\n\n\u003ca name=\"BrowserController+close\"\u003e\u003c/a\u003e\n\n#### `browserController.close()` ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\nGracefully closes the browser and makes sure\nthere will be no lingering browser processes.\n\nEmits 'browserClosed' event.\n\n\n* * *\n\n\u003ca name=\"BrowserController+kill\"\u003e\u003c/a\u003e\n\n#### `browserController.kill()` ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\nImmediately kills the browser process.\n\nEmits 'browserClosed' event.\n\n\n* * *\n\n\u003ca name=\"BrowserController+setCookies\"\u003e\u003c/a\u003e\n\n#### `browserController.setCookies(page, cookies)` ⇒ \u003ccode\u003ePromise.\u0026lt;void\u0026gt;\u003c/code\u003e\n\n| Param | Type |\n| --- | --- |\n| page | \u003ccode\u003eObject\u003c/code\u003e | \n| cookies | \u003ccode\u003eArray.\u0026lt;object\u0026gt;\u003c/code\u003e | \n\n\n* * *\n\n\u003ca name=\"BrowserController+getCookies\"\u003e\u003c/a\u003e\n\n#### `browserController.getCookies(page)` ⇒ \u003ccode\u003ePromise.\u0026lt;Array.\u0026lt;object\u0026gt;\u0026gt;\u003c/code\u003e\n\n| Param | Type |\n| --- | --- |\n| page | \u003ccode\u003eObject\u003c/code\u003e | \n\n\n* * *\n\n\u003ca name=\"BrowserPlugin\"\u003e\u003c/a\u003e\n\n### BrowserPlugin\nThe `BrowserPlugin` serves two purposes. First, it is the base class that\nspecialized controllers like `PuppeteerPlugin` or `PlaywrightPlugin` extend.\nSecond, it allows the user to configure the automation libraries and\nfeed them to [BrowserPool](#BrowserPool) for use.\n\n**Properties**\n\n| Name | Type | Default | Description |\n| --- | --- | --- | --- |\n| [useIncognitoPages] | \u003ccode\u003eboolean\u003c/code\u003e | \u003ccode\u003efalse\u003c/code\u003e | By default pages share the same browser context.  If set to true each page uses its own context that is destroyed once the page is closed or crashes. |\n| [userDataDir] | \u003ccode\u003eobject\u003c/code\u003e |  | Path to a User Data Directory, which stores browser session data like cookies and local storage. |\n\n\n* * *\n\n\u003ca name=\"new_BrowserPlugin_new\"\u003e\u003c/a\u003e\n\n#### `new BrowserPlugin(library, [options])`\n\n| Param | Type | Description |\n| --- | --- | --- |\n| library | \u003ccode\u003eobject\u003c/code\u003e | Each plugin expects an instance of the object with the `.launch()` property.  For Puppeteer, it is the `puppeteer` module itself, whereas for Playwright  it is one of the browser types, such as `puppeteer.chromium`.  `BrowserPlugin` does not include the library. You can choose any version  or fork of the library. It also keeps `browser-pool` installation small. |\n| [options] | \u003ccode\u003eobject\u003c/code\u003e |  |\n| [options.launchOptions] | \u003ccode\u003eobject\u003c/code\u003e | Options that will be passed down to the automation library. E.g.  `puppeteer.launch(launchOptions);`. This is a good place to set  options that you want to apply as defaults. To dynamically override  those options per-browser, see the `preLaunchHooks` of [BrowserPool](#BrowserPool). |\n| [options.proxyUrl] | \u003ccode\u003estring\u003c/code\u003e | Automation libraries configure proxies differently. This helper allows you  to set a proxy URL without worrying about specific implementations.  It also allows you use an authenticated proxy without extra code. |\n\n\n* * *\n\n\u003ca name=\"LaunchContext\"\u003e\u003c/a\u003e\n\n### LaunchContext\n`LaunchContext` holds information about the launched browser. It's useful\nto retrieve the `launchOptions`, the proxy the browser was launched with\nor any other information user chose to add to the `LaunchContext` by calling\nits `extend` function. This is very useful to keep track of browser-scoped\nvalues, such as session IDs.\n\n**Properties**\n\n| Name | Type | Description |\n| --- | --- | --- |\n| id | \u003ccode\u003estring\u003c/code\u003e | To make identification of `LaunchContext` easier, `BrowserPool` assigns  the `LaunchContext` an `id` that's equal to the `id` of the page that  triggered the browser launch. This is useful, because many pages share  a single launch context (single browser). |\n| browserPlugin | [\u003ccode\u003eBrowserPlugin\u003c/code\u003e](#BrowserPlugin) | The `BrowserPlugin` instance used to launch the browser. |\n| launchOptions | \u003ccode\u003eobject\u003c/code\u003e | The actual options the browser was launched with, after changes.  Those changes would be typically made in pre-launch hooks. |\n| [useIncognitoPages] | \u003ccode\u003eboolean\u003c/code\u003e | By default pages share the same browser context.  If set to true each page uses its own context that is destroyed once the page is closed or crashes. |\n| [userDataDir] | \u003ccode\u003eobject\u003c/code\u003e | Path to a User Data Directory, which stores browser session data like cookies and local storage. |\n\n\n* [LaunchContext](#LaunchContext)\n    * [`.proxyUrl`](#LaunchContext+proxyUrl)\n    * [`.proxyUrl`](#LaunchContext+proxyUrl) ⇒ \u003ccode\u003estring\u003c/code\u003e\n    * [`.extend(fields)`](#LaunchContext+extend)\n\n\n* * *\n\n\u003ca name=\"LaunchContext+proxyUrl\"\u003e\u003c/a\u003e\n\n#### `launchContext.proxyUrl`\nSets a proxy URL for the browser.\nUse `undefined` to unset existing proxy URL.\n\n\n| Param | Type |\n| --- | --- |\n| url | \u003ccode\u003estring\u003c/code\u003e | \n\n\n* * *\n\n\u003ca name=\"LaunchContext+proxyUrl\"\u003e\u003c/a\u003e\n\n#### `launchContext.proxyUrl` ⇒ \u003ccode\u003estring\u003c/code\u003e\nReturns the proxy URL of the browser.\n\n\n* * *\n\n\u003ca name=\"LaunchContext+extend\"\u003e\u003c/a\u003e\n\n#### `launchContext.extend(fields)`\nExtend the launch context with any extra fields.\nThis is useful to keep state information relevant\nto the browser being launched. It ensures that\nno internal fields are overridden and should be\nused instead of property assignment.\n\n\n| Param | Type |\n| --- | --- |\n| fields | \u003ccode\u003eobject\u003c/code\u003e | \n\n\n* * *\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapify%2Fbrowser-pool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapify%2Fbrowser-pool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapify%2Fbrowser-pool/lists"}