browser-profiles
# @aitofy/browser-profiles > π **Self-hosted anti-detect browser profiles.** The open-source alternative to AdsPower & Multilogin. > Run locally, own your data, no subscriptions. [](https://www.npmjs.com/package/@aitofy/browser-profiles) [](https://opensource.org/licenses/MIT) [](https://www.typescriptlang.org/) [](https://github.com/aitofy-dev/browser-profiles) ## π― Why browser-profiles? Like **n8n** for automation or **Affine** for notes, this is **AdsPower for developers** β self-hosted, open-source, and privacy-first. | β AdsPower/Multilogin | β browser-profiles | |------------------------|---------------------| | $99+/month | **Free forever** | | Cloud storage (data not yours) | **Local storage** (your data) | | GUI only | **Code-first** (Puppeteer/Playwright) | | Vendor lock-in | **Open source** (MIT) | | No customization | **Full control** | ## β¨ Features - π **Self-hosted** - Data stays on your machine, no cloud dependency - π **Privacy-first** - Zero telemetry, zero tracking - π‘οΈ **Anti-detect** - WebRTC, Canvas, WebGL, Audio fingerprint protection - π **Proxy support** - HTTP, HTTPS, SOCKS5 with auto timezone detection - π¦ **Profile management** - Create, update, delete browser profiles - π **Puppeteer & Playwright** - First-class integration - β‘ **Zero config** - Works out of the box - πͺΆ **Lightweight** - No extensions, pure CDP injection ## π¦ Installation ```bash # Recommended: rebrowser-puppeteer-core (better anti-detect!) npm install @aitofy/browser-profiles rebrowser-puppeteer-core # Or standard puppeteer npm install @aitofy/browser-profiles puppeteer-core ``` ### Anti-Detect Score | Site | Score | Notes | |------|-------|-------| | browserleaks.com | β 100% | All checks passed | | pixelscan.net | β 100% | Hardware fingerprint passed | | browserscan.net | β οΈ 95% | Bot Control -5% (Puppeteer limitation) | | creepjs | β οΈ 85% | Minor deductions | > **Note**: 95% is the best achievable with Puppeteer/Playwright. 100% requires modified Chromium (like AdsPower). ## π» CLI Tool Install globally to use the CLI: ```bash npm install -g @aitofy/browser-profiles ``` ### Commands ```bash # List all profiles browser-profiles list # Create a new profile browser-profiles create my-account browser-profiles create my-account --proxy http://user:[email protected]:8080 # Open browser with a profile browser-profiles open <profile-id> # Quick launch (no profile needed) browser-profiles launch browser-profiles launch --proxy http://proxy.com:8080 # Show profile details browser-profiles info <profile-id> # Delete a profile browser-profiles delete <profile-id> # Show storage path browser-profiles path ``` ## π Quick Start ### β‘ 30-Second Example ```typescript import { quickLaunch } from '@aitofy/browser-profiles'; // Launch anti-detect browser with proxy (timezone auto-detected!) const { page, close } = await quickLaunch({ proxy: { type: 'http', host: 'your-proxy.com', port: 8080 }, }); await page.goto('https://browserscan.net'); await page.screenshot({ path: 'proof.png' }); await close(); ``` That's it! π Browser fingerprint is protected, IP is hidden, timezone matches proxy location. --- ### Profile Management ```typescript import { BrowserProfiles } from '@aitofy/browser-profiles'; const profiles = new BrowserProfiles(); // Create a profile (saved to ~/.aitofy/browser-profiles/) const profile = await profiles.create({ name: 'My Profile', proxy: { type: 'http', host: 'proxy.example.com', port: 8080, }, }); // Launch browser const { wsEndpoint, close } = await profiles.launch(profile.id); // ... automation work ... await close(); ``` ### π Custom Profile IDs You can define your own custom profile IDs instead of using auto-generated ones: ```typescript // Create profile with custom ID const profile = await profiles.create({ id: 'google-main', // Custom ID (alphanumeric + hyphen/underscore) name: 'Google Account', }); // Launch by custom ID directly const { wsEndpoint } = await profiles.launch('google-main'); ``` **Custom ID rules:** - 1-64 characters - Alphanumeric with hyphens and underscores only (a-z, A-Z, 0-9, -, _) - Must be unique ### π Launch by Profile Name You can now launch browsers using the profile **name** instead of ID: ```typescript // Create profile await profiles.create({ name: 'Facebook Account' }); // Launch by name (case-insensitive) const { wsEndpoint } = await profiles.launchByName('Facebook Account'); // Or use launchByIdOrName (works with both ID and name) await profiles.launchByIdOrName('google-main'); // By ID await profiles.launchByIdOrName('Facebook Account'); // By name ``` ### With Puppeteer ```typescript import { withPuppeteer } from '@aitofy/browser-profiles/puppeteer'; const { browser, page, close } = await withPuppeteer({ profile: 'my-profile-id', // or profile name }); await page.goto('https://whoer.net'); await page.screenshot({ path: 'screenshot.png' }); await close(); ``` ### Quick Launch (No Profile Needed) ```typescript import { quickLaunch } from '@aitofy/browser-profiles/puppeteer'; const { browser, page, close } = await quickLaunch({ proxy: { type: 'http', host: 'proxy.example.com', port: 8080, }, // timezone is now AUTO-DETECTED from proxy IP! // No need to specify manually. If no proxy, system timezone is used. fingerprint: { platform: 'Win32', // Spoof as Windows hardwareConcurrency: 8, // Spoof CPU cores language: 'en-US', }, }); // Output: [browser-profiles] π Auto-detected timezone: America/New_York (New York, United States) await page.goto('https://browserscan.net'); await close(); ``` ### With Playwright ```typescript import { withPlaywright } from '@aitofy/browser-profiles/playwright'; const { browser, page, close } = await withPlaywright({ profile: 'my-profile-id', }); await page.goto('https://example.com'); await close(); ``` ### π v0.2.0: Advanced Features #### Temporary Sessions (No Profile Persistence) ```typescript import { createSession } from '@aitofy/browser-profiles/puppeteer'; // Quick session with random fingerprint - perfect for scraping const session = await createSession({ temporary: true, randomFingerprint: true, // Random platform, language, CPU cores proxy: { type: 'http', host: 'proxy.com', port: 8080 }, }); await session.page.goto('https://example.com'); await session.close(); // Cleanup ``` #### Patch Existing Pages ```typescript import { patchPage } from '@aitofy/browser-profiles/puppeteer'; // Apply anti-detect patches to any page await patchPage(page, { webdriver: true, // Hide webdriver flag plugins: true, // Spoof Chrome plugins chrome: true, // Fix chrome object webrtc: true, // WebRTC leak protection fingerprint: { platform: 'Win32', hardwareConcurrency: 8 }, }); ``` #### Generate Fingerprints On-Demand ```typescript import { generateFingerprint, getFingerprintScripts } from '@aitofy/browser-profiles'; // Generate a realistic fingerprint const fp = generateFingerprint({ platform: 'macos', gpu: 'apple', screen: 'retina', language: 'ja-JP', }); console.log(fp.userAgent); // Mozilla/5.0 (Macintosh... console.log(fp.webgl.renderer); // ANGLE (Apple, Apple M1 Pro... // Use with any page const scripts = getFingerprintScripts(fp); await page.evaluateOnNewDocument(scripts); ``` #### Standalone Chrome Launch ```typescript import { launchChromeStandalone } from '@aitofy/browser-profiles'; import puppeteer from 'puppeteer-core'; // Launch Chrome without profile management const { wsEndpoint, close } = await launchChromeStandalone({ headless: false, proxy: { type: 'http', host: 'proxy.com', port: 8080 }, }); const browser = await puppeteer.connect({ browserWSEndpoint: wsEndpoint }); await close(); ``` #### Inject Your Own Puppeteer ```typescript import puppeteer from 'rebrowser-puppeteer-core'; import { withPuppeteer } from '@aitofy/browser-profiles/puppeteer'; // Use your own puppeteer instance const { browser, page } = await withPuppeteer({ profile: 'my-profile', puppeteer, // β Inject here }); ``` ### π Profile Management Profiles are saved locally to `~/.aitofy/browser-profiles/` and persist between sessions. ```typescript import { BrowserProfiles } from '@aitofy/browser-profiles'; const profiles = new BrowserProfiles(); // ===== CREATE ===== const profile = await profiles.create({ name: 'Facebook Account 1', proxy: { type: 'http', host: 'proxy.example.com', port: 8080 }, tags: ['facebook', 'marketing'], }); // ===== LIST ALL ===== const allProfiles = await profiles.list(); console.log(`Total: ${allProfiles.length} profiles`); // ===== LIST BY TAG ===== const fbProfiles = await profiles.list({ tags: ['facebook'] }); // ===== GET BY ID ===== const myProfile = await profiles.get(profile.id); // ===== UPDATE ===== await profiles.update(profile.id, { name: 'Facebook Account 1 - Updated', proxy: { type: 'socks5', host: 'new-proxy.com', port: 1080 }, }); // ===== LAUNCH BROWSER ===== const { wsEndpoint, close } = await profiles.launch(profile.id); // ... do automation ... await close(); // ===== DUPLICATE ===== const cloned = await profiles.duplicate(profile.id, 'Facebook Account 2'); // ===== EXPORT / IMPORT ===== const json = await profiles.export(profile.id); const imported = await profiles.import(json); // ===== DELETE ===== await profiles.delete(profile.id); ``` ### π Groups (Organization) ```typescript // Create groups const group = await profiles.createGroup('TikTok Shop', 'All TikTok accounts'); // Move profile to group await profiles.moveToGroup(profile.id, group.id); // List groups const groups = await profiles.listGroups(); // List profiles in group const tikTokProfiles = await profiles.list({ groupId: group.id }); ``` ### ExTower Integration ```typescript import { ExTowerClient } from '@aitofy/browser-profiles/extower'; import puppeteer from 'puppeteer-core'; const client = new ExTowerClient({ baseUrl: 'http://localhost:50325', // default }); // Create profile in ExTower const { id } = await client.createProfile({ name: 'TikTok Shop 1', proxy: { type: 'http', host: 'proxy.example.com', port: 8080, }, }); // Launch browser const { puppeteer: wsEndpoint } = await client.launchBrowser(id); // Connect Puppeteer const browser = await puppeteer.connect({ browserWSEndpoint: wsEndpoint, }); const page = await browser.newPage(); await page.goto('https://seller-us.tiktok.com'); ``` ## π API Reference ### BrowserProfiles Main class for managing browser profiles. ```typescript const profiles = new BrowserProfiles({ storagePath: '~/.aitofy/browser-profiles', // Default: ~/.aitofy/browser-profiles chromePath: '/path/to/chrome', // Custom Chrome path (optional) defaultTimezone: 'UTC', // Default timezone for new profiles }); ``` **Default storage locations:** - macOS: `~/.aitofy/browser-profiles` - Linux: `~/.aitofy/browser-profiles` - Windows: `C:\Users\<user>\.aitofy\browser-profiles` #### Methods | Method | Description | |--------|-------------| | `create(config)` | Create a new profile (supports custom ID via `config.id`) | | `get(id)` | Get profile by ID | | `getByName(name)` | Get profile by name (case-insensitive) | | `getByIdOrName(idOrName)` | Get profile by ID or name | | `list(options?)` | List all profiles | | `update(id, updates)` | Update profile | | `delete(id)` | Delete profile | | `launch(id, options?)` | Launch browser by profile ID | | `launchByName(name, options?)` | Launch browser by profile name | | `launchByIdOrName(idOrName, options?)` | Launch browser by ID or name | | `close(id)` | Close running browser | | `closeAll()` | Close all browsers | | `duplicate(id)` | Duplicate profile | | `export(id)` | Export to JSON | | `import(json)` | Import from JSON | ### Profile Configuration ```typescript interface ProfileConfig { id?: string; // Custom profile ID (auto-generated if omitted) name: string; // Profile name proxy?: ProxyConfig; // Proxy settings timezone?: string; // e.g., "America/New_York" cookies?: ProfileCookie[]; // Cookies to inject fingerprint?: FingerprintConfig; // Fingerprint settings startUrls?: string[]; // URLs to open on launch tags?: string[]; // Tags for organization groupId?: string; // Group for organization } ``` ### Proxy Configuration ```typescript interface ProxyConfig { type: 'http' | 'https' | 'socks5'; host: string; port: number | string; username?: string; password?: string; } ``` ### Launch Options ```typescript interface LaunchOptions { headless?: boolean; // Run headless (default: false) chromePath?: string; // Custom Chrome path args?: string[]; // Additional Chrome args extensions?: string[]; // Extension paths to load defaultViewport?: { width: number; height: number } | null; slowMo?: number; // Slow down by ms timeout?: number; // Launch timeout } ``` ## π Anti-Detect Features All fingerprint protections are **hardcoded** and injected via CDP - no extensions required! ### π€ Automation Detection Bypass Comprehensive protection against bot detection: | Check | Status | Description | |-------|--------|-------------| | `navigator.webdriver` | β Hidden | Returns `undefined` | | `window.chrome` | β Faked | Complete chrome object | | `chrome.runtime` | β Faked | Runtime object present | | `chrome.csi()` | β Faked | Timing function | | `chrome.loadTimes()` | β Faked | Page load metrics | | `navigator.plugins` | β Faked | 3 default Chrome plugins | | `navigator.connection` | β Faked | 4G connection info | | `navigator.getBattery()` | β Faked | Battery status API | | `navigator.permissions` | β Mocked | Permission query handling | ### WebRTC Leak Protection Automatically prevents WebRTC from leaking your real IP address. Works even when using proxy! ### Canvas Fingerprint Protection Adds random noise to canvas data to prevent tracking. ### WebGL Fingerprint Protection Spoofs WebGL parameters and adds noise to buffer data: - Randomizes vendor/renderer strings - Spoofs GPU parameters - Adds noise to WebGL buffer data ### AudioContext Fingerprint Protection Adds tiny noise to audio data without affecting audio quality. ### Timezone Spoofing ```typescript const profile = await profiles.create({ name: 'US Profile', timezone: 'America/New_York', // Browser reports this timezone }); ``` ### Navigator Spoofing Customize browser navigator properties: ```typescript const profile = await profiles.create({ name: 'Custom Profile', fingerprint: { language: 'en-US', platform: 'Win32', hardwareConcurrency: 8, deviceMemory: 16, }, }); ``` ### Proxy with Authentication Handles authenticated proxies transparently: ```typescript const profile = await profiles.create({ name: 'With Auth Proxy', proxy: { type: 'http', host: 'proxy.example.com', port: 8080, username: 'user', // β Auth handled automatically password: 'password', }, }); ``` ## β Verified Test Results Tested on 2026-01-08 with the following fingerprint testing sites: | Property | Spoofed Value | Verification | |----------|---------------|--------------| | Timezone | America/New_York | β BrowserScan | | Platform | Win32 | β BrowserLeaks | | CPU Cores | 8 | β PixelScan | | Device Memory | 16GB | β PixelScan | | Language | en-US | β All sites | | WebRTC IP | Hidden | β BrowserLeaks | | Webdriver | Hidden | β All sites | | Plugins | 5 | β BrowserLeaks | | Connection API | 4g | β Verified | | Chrome Object | Complete | β Verified | | Chrome.csi | Present | β Verified | | Chrome.loadTimes | Present | β Verified | **Sites tested:** - β [browserscan.net](https://browserscan.net) - β [browserleaks.com](https://browserleaks.com/javascript) - β [pixelscan.net](https://pixelscan.net) - β [creepjs](https://abrahamjuliot.github.io/creepjs/) ## π Comparison | Feature | browser-profiles | AdsPower | Multilogin | puppeteer-extra | |---------|-----------------|----------|------------|-----------------| | **Open Source** | β MIT | β Paid | β Paid | β MIT | | **Price** | **FREE** | $9-50/mo | $99-199/mo | Free | | **Anti-Detect Score** | 95% | 100% | 100% | ~80% | | **Profile Storage** | β | β | β | β | | **Proxy Auth** | β | β | β | β | | **Auto Timezone** | β | β | β | β | | **WebRTC Protection** | β | β | β | β οΈ Basic | | **Canvas Noise** | β | β | β | β οΈ Basic | | **TypeScript** | β | β | β | β οΈ Partial | | **npm Package** | β | β | β | β | | **Puppeteer Integration** | β | β | β οΈ | β | | **Playwright Integration** | β | β | β οΈ | β | | **Cloud Sync** | π Coming | β | β | β | | **GUI** | β | β | β | β | ### Why 95% vs 100%? AdsPower and Multilogin achieve 100% by using **modified Chromium binaries**. Our library uses standard Chrome with JS injection, which has a fundamental ~5% detection limitation on advanced sites like BrowserScan. **For most use cases (social media, e-commerce, scraping), 95% is sufficient.** ## π Security ### Data Storage - All data stored **locally** at `~/.aitofy/browser-profiles/` - **Zero telemetry** - no data sent to any server - Profile configs stored as JSON files - Chrome user data (passwords, autofill) encrypted by Chrome itself ### Future: E2E Encryption (Coming Soon) ```typescript const profiles = new BrowserProfiles({ encryption: { enabled: true, masterKey: 'your-secret-key', } }); ``` - AES-256-GCM encryption for sensitive data - Optional cloud sync with end-to-end encryption - Only you (or people you share the key with) can decrypt ## π v0.2.5: Full Type Support ### Native Type Re-exports Starting from v0.2.5, `PuppeteerPage` and `PlaywrightPage` are **native types** re-exported from `puppeteer-core` and `playwright`. You now have access to ALL APIs directly: ```typescript import { withPuppeteer, PuppeteerPage } from '@aitofy/browser-profiles'; const { page, close } = await withPuppeteer({ profile: 'my-profile' }); // β Full API access - no workarounds needed! await page.setRequestInterception(true); page.on('request', (req) => { if (req.resourceType() === 'image') { req.abort(); } else { req.continue(); } }); const cookies = await page.cookies(); await page.setCookie({ name: 'session', value: '123', domain: '.example.com' }); await close(); ``` **For Playwright:** ```typescript import { withPlaywright, PlaywrightPage } from '@aitofy/browser-profiles'; const { page, close } = await withPlaywright({ profile: 'my-profile' }); // β Full Playwright API! await page.route('**/*', (route) => { if (route.request().resourceType() === 'image') { route.abort(); } else { route.continue(); } }); await page.reload(); await page.waitForTimeout(1000); await close(); ``` ### Exported Types All commonly used types are re-exported for convenience: | Puppeteer Types | Playwright Types | |-----------------|------------------| | `PuppeteerPage` | `PlaywrightPage` | | `PuppeteerBrowser` | `PlaywrightBrowser` | | `HTTPRequest` | `PlaywrightContext` | | `HTTPResponse` | `PlaywrightRequest` | | `Cookie` | `PlaywrightResponse`, `Route` | ## π€ Contributing Contributions are welcome! Please read our [Contributing Guide](https://github.com/aitofy-dev/browser-profiles/blob/main/CONTRIBUTING.md). ## π License MIT Β© [Aitofy](https://aitofy.dev) --- <p align="center"> Made with β€οΈ by <a href="https://aitofy.dev">Aitofy</a> </p>