{"id":15306073,"url":"https://github.com/devalexanderdaza/puppeteer-extends","last_synced_at":"2025-10-27T17:31:27.079Z","repository":{"id":40264343,"uuid":"421237413","full_name":"devalexanderdaza/puppeteer-extends","owner":"devalexanderdaza","description":"Easy manage and instance a puppeteer using a singleton pattern. Minimal configuration implemented for install and use.","archived":false,"fork":false,"pushed_at":"2024-11-26T15:14:57.000Z","size":1607,"stargazers_count":2,"open_issues_count":9,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-01-20T21:38:01.843Z","etag":null,"topics":["puppet-module","puppeteer","puppeteer-screenshot"],"latest_commit_sha":null,"homepage":"https://devalexanderdaza.github.io/puppeteer-extends/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devalexanderdaza.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-10-26T01:18:44.000Z","updated_at":"2024-08-28T15:01:06.000Z","dependencies_parsed_at":"2023-02-07T04:45:22.756Z","dependency_job_id":null,"html_url":"https://github.com/devalexanderdaza/puppeteer-extends","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devalexanderdaza%2Fpuppeteer-extends","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devalexanderdaza%2Fpuppeteer-extends/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devalexanderdaza%2Fpuppeteer-extends/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devalexanderdaza%2Fpuppeteer-extends/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devalexanderdaza","download_url":"https://codeload.github.com/devalexanderdaza/puppeteer-extends/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238533288,"owners_count":19488159,"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":["puppet-module","puppeteer","puppeteer-screenshot"],"created_at":"2024-10-01T08:04:21.601Z","updated_at":"2025-10-27T17:31:27.073Z","avatar_url":"https://github.com/devalexanderdaza.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# puppeteer-extends\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Build Status](https://github.com/devalexanderdaza/puppeteer-extends/actions/workflows/ci.yml/badge.svg)](https://github.com/devalexanderdaza/puppeteer-extends/actions/workflows/ci.yml)\n[![NPM Package](https://img.shields.io/npm/v/puppeteer-extends.svg)](https://npmjs.org/package/puppeteer-extends)\n\n\u003e Modern, factory-based management for Puppeteer with advanced navigation features. Ideal for web scraping, testing, and automation.\n\n## Features\n\n- 🏭 **Browser Factory** - Multiple browser instances with intelligent reuse\n- 🧭 **Enhanced Navigation** - CloudFlare bypass, retry mechanisms, and more\n- 📝 **TypeScript Support** - Full type definitions for better DX\n- 🔄 **Singleton Compatibility** - Maintains backward compatibility\n- 🛡️ **Stealth Mode** - Integrated puppeteer-extra-plugin-stealth\n\n## Installation\n\n```bash\npnpm install puppeteer-extends\n```\n\n## Basic Usage\n\n```typescript\nimport { PuppeteerExtends, Logger } from 'puppeteer-extends';\nimport path from 'path';\n\nconst main = async () =\u003e {\n  // Get browser instance with options\n  const browser = await PuppeteerExtends.getBrowser({\n    isHeadless: true,\n    isDebug: true\n  });\n  \n  // Create new page\n  const page = await browser.newPage();\n  \n  // Navigate with enhanced features (CloudFlare bypass, retries)\n  await PuppeteerExtends.goto(page, 'https://example.com', {\n    maxRetries: 2,\n    timeout: 30000\n  });\n  \n  // Take screenshot\n  await page.screenshot({ \n    path: path.join(__dirname, 'screenshot.png') \n  });\n  \n  // Clean up\n  await PuppeteerExtends.closePage(page);\n  await PuppeteerExtends.closeBrowser();\n};\n\nmain().catch(console.error);\n```\n\n## Multiple Browser Instances\n\n```typescript\nimport { PuppeteerExtends } from 'puppeteer-extends';\n\nconst main = async () =\u003e {\n  // Create two browser instances with different configurations\n  const mainBrowser = await PuppeteerExtends.getBrowser({\n    instanceId: 'main',\n    isHeadless: true\n  });\n  \n  const proxyBrowser = await PuppeteerExtends.getBrowser({\n    instanceId: 'proxy',\n    isHeadless: true,\n    customArguments: [\n      '--proxy-server=http://my-proxy.com:8080',\n      '--no-sandbox'\n    ]\n  });\n  \n  // Work with both browsers\n  const mainPage = await mainBrowser.newPage();\n  const proxyPage = await proxyBrowser.newPage();\n  \n  // Clean up specific browser\n  await PuppeteerExtends.closeBrowser('proxy');\n  \n  // Or close all browsers at once\n  await PuppeteerExtends.closeAllBrowsers();\n};\n```\n\n## Advanced Navigation Features\n\n```typescript\nimport { PuppeteerExtends } from 'puppeteer-extends';\n\nconst scrape = async () =\u003e {\n  const browser = await PuppeteerExtends.getBrowser();\n  const page = await browser.newPage();\n  \n  // Navigation with retries and custom options\n  const success = await PuppeteerExtends.goto(page, 'https://example.com', {\n    waitUntil: ['networkidle0'],\n    timeout: 60000,\n    maxRetries: 3,\n    retryDelay: 5000,\n    isDebug: true\n  });\n  \n  if (success) {\n    // Wait for specific element with timeout\n    const elementVisible = await PuppeteerExtends.waitForSelector(\n      page, \n      '.content-loaded', \n      10000\n    );\n    \n    if (elementVisible) {\n      // Extract data\n      const data = await page.evaluate(() =\u003e {\n        return {\n          title: document.title,\n          content: document.querySelector('.content')?.textContent\n        };\n      });\n      \n      console.log('Scraped data:', data);\n    }\n  }\n  \n  await PuppeteerExtends.closePage(page);\n  await PuppeteerExtends.closeBrowser();\n};\n```\n\n## Customizing Logger\n\n```typescript\nimport { Logger } from 'puppeteer-extends';\nimport path from 'path';\n\n// Set custom log directory\nLogger.configure(path.join(__dirname, 'custom-logs'));\n\n// Use logger\nLogger.info('Starting browser');\nLogger.debug('Debug information');\nLogger.warn('Warning message');\nLogger.error('Error occurred', new Error('Something went wrong'));\n```\n\n## Plugin System\n\npuppeteer-extends v1.7.0 introduces a powerful plugin system that allows extending functionality through lifecycle hooks:\n\n```typescript\nimport { PuppeteerExtends, StealthPlugin, ProxyPlugin } from 'puppeteer-extends';\n\n// Register stealth plugin for improved anti-bot protection\nawait PuppeteerExtends.registerPlugin(new StealthPlugin({\n  hideWebDriver: true,\n  hideChromeRuntime: true\n}));\n\n// Register proxy rotation plugin\nawait PuppeteerExtends.registerPlugin(new ProxyPlugin({\n  proxies: [\n    { host: '123.45.67.89', port: 8080, username: 'user', password: 'pass' },\n    { host: '98.76.54.32', port: 8080 },\n  ],\n  rotationStrategy: 'sequential',\n  rotateOnNavigation: true,\n  rotateOnError: true\n}));\n\n// Continue with normal usage - plugins will be active\nconst browser = await PuppeteerExtends.getBrowser();\nconst page = await browser.newPage();\n// ...\n```\n\n### Built-in Plugins\n\n| Plugin | Description |\n|--------|-------------|\n| `StealthPlugin` | Enhances anti-bot detection protection |\n| `ProxyPlugin` | Provides proxy rotation with multiple strategies |\n\n### Creating Custom Plugins\n\nYou can create custom plugins by implementing the `PuppeteerPlugin` interface:\n\n```typescript\nimport { PuppeteerPlugin, PluginContext } from 'puppeteer-extends';\n\nclass MyCustomPlugin implements PuppeteerPlugin {\n  name = 'my-custom-plugin';\n  \n  // Called when plugin is registered\n  async initialize(options?: any): Promise\u003cvoid\u003e {\n    console.log('Plugin initialized with options:', options);\n  }\n  \n  // Called before browser launch\n  async onBeforeBrowserLaunch(options: any, context: PluginContext): Promise\u003cany\u003e {\n    // Modify launch options if needed\n    return {\n      ...options,\n      args: [...options.args, '--disable-features=site-per-process']\n    };\n  }\n  \n  // Called when a new page is created\n  async onPageCreated(page: Page, context: PluginContext): Promise\u003cvoid\u003e {\n    await page.evaluateOnNewDocument(() =\u003e {\n      // Execute code in the page context\n    });\n  }\n  \n  // Called before navigation\n  async onBeforeNavigation(page: Page, url: string, options: any, context: PluginContext): Promise\u003cvoid\u003e {\n    console.log(`Navigating to: ${url}`);\n  }\n  \n  // Handle errors\n  async onError(error: Error, context: PluginContext): Promise\u003cboolean\u003e {\n    console.error('Plugin caught error:', error);\n    return false; // Return true if error was handled\n  }\n  \n  // Called when plugin is unregistered\n  async cleanup(): Promise\u003cvoid\u003e {\n    console.log('Plugin cleanup');\n  }\n}\n\n// Register the custom plugin\nawait PuppeteerExtends.registerPlugin(new MyCustomPlugin(), { \n  customOption: 'value' \n});\n```\n\n### Available Plugin Hooks\n\n| Hook | Description |\n|------|-------------|\n| `initialize` | Called when plugin is registered |\n| `cleanup` | Called when plugin is unregistered |\n| `onBeforeBrowserLaunch` | Before browser instance is created |\n| `onAfterBrowserLaunch` | After browser instance is created |\n| `onBeforeBrowserClose` | Before browser instance is closed |\n| `onPageCreated` | When a new page is created |\n| `onBeforePageClose` | Before a page is closed |\n| `onBeforeNavigation` | Before navigation to a URL |\n| `onAfterNavigation` | After navigation completes (success or failure) |\n| `onError` | When an error occurs in any operation |\n\n## Session Management\n\npuppeteer-extends v1.7.0 introduces powerful session management capabilities, allowing you to persist cookies, localStorage, and other browser state between runs:\n\n```typescript\nimport { PuppeteerExtends, SessionManager } from 'puppeteer-extends';\n\n// Create a session manager\nconst sessionManager = new SessionManager({\n  name: 'my-session',\n  sessionDir: './sessions',\n  persistCookies: true,\n  persistLocalStorage: true,\n  domains: ['example.com'] // Only store cookies for these domains\n});\n\n// Get browser and create page\nconst browser = await PuppeteerExtends.getBrowser();\nconst page = await browser.newPage();\n\n// Apply session data to page (cookies, localStorage, etc.)\nawait sessionManager.applySession(page);\n\n// Navigate somewhere\nawait PuppeteerExtends.goto(page, 'https://example.com/login');\n\n// Perform login or other actions that modify session\nawait page.type('#username', 'myuser');\nawait page.type('#password', 'mypassword');\nawait page.click('#login-button');\n\n// Wait for login to complete\nawait PuppeteerExtends.waitForNavigation(page);\n\n// Extract and save session data (cookies, localStorage, etc.)\nawait sessionManager.extractSession(page);\n\n// Next time you run your script, the session will be loaded automatically\n```\n\n### Using the SessionPlugin\n\nFor more integrated session management, use the built-in SessionPlugin:\n\n```typescript\nimport { PuppeteerExtends } from 'puppeteer-extends';\nimport { SessionPlugin } from 'puppeteer-extends/plugins';\n\n// Register the session plugin\nawait PuppeteerExtends.registerPlugin(new SessionPlugin({\n  name: 'my-session',\n  persistCookies: true,\n  persistLocalStorage: true,\n  extractAfterNavigation: true, // Auto-save after each navigation\n  applyBeforeNavigation: true   // Auto-apply before each navigation\n}));\n\n// Session management is now automatic\nconst browser = await PuppeteerExtends.getBrowser();\nconst page = await browser.newPage();\n\n// Navigate anywhere - session will be applied/extracted automatically\nawait PuppeteerExtends.goto(page, 'https://example.com');\n```\n\n### Session Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `sessionDir` | string | `\"./tmp/puppeteer-extends/sessions\"` | Directory to store session files |\n| `name` | string | `\"default\"` | Session name (used for file name) |\n| `persistCookies` | boolean | `true` | Whether to save/load cookies |\n| `persistLocalStorage` | boolean | `true` | Whether to save/load localStorage |\n| `persistSessionStorage` | boolean | `false` | Whether to save/load sessionStorage |\n| `persistUserAgent` | boolean | `true` | Whether to save/load userAgent |\n| `domains` | string[] | `undefined` | Domains to include when saving cookies |\n| `extractAfterNavigation`* | boolean | `true` | Save session after each navigation |\n| `applyBeforeNavigation`* | boolean | `true` | Apply session before each navigation |\n\n*Only available in SessionPlugin\n\n## Event System\n\npuppeteer-extends v1.7.0 includes a powerful event system that allows you to react to various lifecycle events:\n\n```typescript\nimport { PuppeteerExtends, Events, PuppeteerEvents } from 'puppeteer-extends';\n\n// Listen for browser creation\nEvents.on(PuppeteerEvents.BROWSER_CREATED, (params) =\u003e {\n  console.log(`Browser created with ID: ${params.instanceId}`);\n});\n\n// Listen for navigation events\nEvents.on(PuppeteerEvents.NAVIGATION_STARTED, (params) =\u003e {\n  console.log(`Navigation started to: ${params.url}`);\n});\n\nEvents.on(PuppeteerEvents.NAVIGATION_SUCCEEDED, (params) =\u003e {\n  console.log(`Successfully navigated to: ${params.url}`);\n});\n\n// Listen for errors\nEvents.on(PuppeteerEvents.ERROR, (params) =\u003e {\n  console.error(`Error in ${params.source}: ${params.error.message}`);\n});\n\n// Use one-time listeners\nEvents.once(PuppeteerEvents.PAGE_CREATED, (params) =\u003e {\n  console.log('First page created!');\n});\n\n// Normal usage of puppeteer-extends will trigger these events\nconst browser = await PuppeteerExtends.getBrowser();\nconst page = await browser.newPage();\nawait PuppeteerExtends.goto(page, 'https://example.com');\n```\n\n### Supported Events\n\n| Event Type | Description |\n|------------|-------------|\n| `BROWSER_CREATED` | Browser instance created |\n| `BROWSER_CLOSED` | Browser instance closed |\n| `PAGE_CREATED` | New page created |\n| `PAGE_CLOSED` | Page closed |\n| `NAVIGATION_STARTED` | Navigation to URL started |\n| `NAVIGATION_SUCCEEDED` | Navigation completed successfully |\n| `NAVIGATION_FAILED` | Navigation failed after retries |\n| `ERROR` | Generic error occurred |\n| `NAVIGATION_ERROR` | Error during navigation |\n| `BROWSER_ERROR` | Error in browser operations |\n| `PAGE_ERROR` | Error in page operations |\n| `SESSION_APPLIED` | Session data applied to page |\n| `SESSION_EXTRACTED` | Session data extracted from page |\n| `SESSION_CLEARED` | Session data cleared |\n| `PLUGIN_REGISTERED` | Plugin registered |\n| `PLUGIN_UNREGISTERED` | Plugin unregistered |\n\n### Asynchronous Event Handling\n\nYou can use asynchronous event handlers and wait for them:\n\n```typescript\n// Register async event handler\nEvents.on(PuppeteerEvents.NAVIGATION_SUCCEEDED, async (params) =\u003e {\n  // Do something asynchronous\n  await saveToDatabase(params.url);\n});\n\n// Emit event and wait for all handlers to complete\nawait Events.emitAsync(PuppeteerEvents.CUSTOM_EVENT, { data: 'value' });\n```\n\n## Captcha Handling\n\npuppeteer-extends v1.7.0 introduces sophisticated captcha detection and solving capabilities:\n\n```typescript\nimport { PuppeteerExtends, CaptchaService } from 'puppeteer-extends';\nimport { CaptchaPlugin } from 'puppeteer-extends/plugins';\n\n// Register the captcha plugin with automatic handling\nawait PuppeteerExtends.registerPlugin(new CaptchaPlugin({\n  service: CaptchaService.TWOCAPTCHA, // or CaptchaService.ANTICAPTCHA\n  apiKey: 'your-api-key',\n  autoDetect: true,   // Auto-detect captchas on page load\n  autoSolve: true     // Auto-solve detected captchas\n}));\n\n// Get browser and create page\nconst browser = await PuppeteerExtends.getBrowser();\nconst page = await browser.newPage();\n\n// Navigate to a page - captchas will be automatically detected and solved\nawait PuppeteerExtends.goto(page, 'https://example.com/with-captcha');\n\n// You can also handle captchas manually\nconst plugin = PuppeteerExtends.getPlugin('captcha-plugin');\nconst captchaHelper = plugin.getCaptchaHelper();\n\n// Detect captchas\nconst captchas = await captchaHelper.detectCaptchas(page);\n\n// Solve a specific captcha\nif (captchas.recaptchaV2.length \u003e 0) {\n  const solution = await captchaHelper.solveRecaptchaV2(page, captchas.recaptchaV2[0]);\n  console.log(`Solved captcha: ${solution.token}`);\n}\n```\n\n### Supported Captcha Types\n\n| Type | Description |\n|------|-------------|\n| `RECAPTCHA_V2` | Standard and invisible reCAPTCHA v2 |\n| `RECAPTCHA_V3` | Score-based reCAPTCHA v3 |\n| `HCAPTCHA` | hCaptcha challenges |\n| `IMAGE_CAPTCHA` | Traditional text/image captchas |\n| `FUNCAPTCHA` | Arkose Labs FunCaptcha |\n| `TURNSTILE` | Cloudflare Turnstile |\n\n### Supported Services\n\n| Service | Description |\n|---------|-------------|\n| `TWOCAPTCHA` | [2Captcha](https://2captcha.com/) service |\n| `ANTICAPTCHA` | [Anti-Captcha](https://anti-captcha.com/) service |\n\n### CaptchaPlugin Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `service` | CaptchaService | - | Captcha solving service to use |\n| `apiKey` | string | - | API key for the service |\n| `autoDetect` | boolean | `true` | Auto-detect captchas on page load |\n| `autoSolve` | boolean | `true` | Auto-solve detected captchas |\n| `timeout` | number | `120` | Timeout for solving (seconds) |\n| `ignoreUrls` | string[] | `[]` | URLs to ignore when detecting captchas |\n\n## API Reference\n\n### PuppeteerExtends\n\n| Method | Description |\n|--------|-------------|\n| `getBrowser(options?)` | Get or create browser instance |\n| `closeBrowser(instanceId?)` | Close specific browser |\n| `closeAllBrowsers()` | Close all browser instances |\n| `goto(page, url, options?)` | Navigate to URL with enhanced features |\n| `waitForNavigation(page, options?)` | Wait for navigation to complete |\n| `waitForSelector(page, selector, timeout?)` | Wait for element to be visible |\n| `closePage(page)` | Close page safely |\n\n### BrowserOptions\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `isHeadless` | boolean | `true` | Launch browser in headless mode |\n| `isDebug` | boolean | `false` | Enable debug logging |\n| `customArguments` | string[] | `DEFAULT_BROWSER_ARGS` | Custom browser launch arguments |\n| `userDataDir` | string | `./tmp/puppeteer-extends` | User data directory path |\n| `instanceId` | string | `\"default\"` | Browser instance identifier |\n\n### NavigationOptions\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `waitUntil` | string[] | `[\"load\", \"networkidle0\"]` | Navigation completion events |\n| `timeout` | number | `30000` | Navigation timeout (ms) |\n| `maxRetries` | number | `1` | Maximum retry attempts |\n| `retryDelay` | number | `5000` | Delay between retries (ms) |\n| `isDebug` | boolean | `false` | Enable debug logging |\n| `headers` | object | `{}` | Custom request headers |\n\n## Testing\n\n```bash\n# Run all tests\npnpm run test\n\n# Run with coverage\npnpm run test:coverage\n\n# Run in watch mode\npnpm run test:watch\n```\n\n## License\n\n[Apache-2.0](https://opensource.org/licenses/Apache-2.0)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevalexanderdaza%2Fpuppeteer-extends","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevalexanderdaza%2Fpuppeteer-extends","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevalexanderdaza%2Fpuppeteer-extends/lists"}