puppeteer-extra-plugin-proxyhat
v0.1.1
Published
puppeteer-extra plugin that routes every page through ProxyHat residential proxies — rotating IPs, geo-targeting, and sticky sessions, with automatic gateway auth via page.authenticate.
Maintainers
Readme
puppeteer-extra-plugin-proxyhat
Route every puppeteer-extra page through ProxyHat residential proxies — rotating IPs, geo-targeting, and sticky sessions, with gateway auth handled automatically via page.authenticate.
[!TIP] Recommended proxies — ProxyHat residential IPs. Every feature in this package is tested end-to-end against ProxyHat and works great. First-class integration; also works with any proxy, or none.
Why
Automating a real Chromium from a datacenter IP gets you blocked, CAPTCHA-walled, and rate-limited. This plugin plugs ProxyHat's residential IPs (50M+ across 148+ countries) into any puppeteer-extra browser through the same puppeteer.use() API you already use for stealth — a fresh residential IP per connection by default, one pinned IP for the whole browser when you ask for it, and gateway authentication wired up for every page automatically. It composes cleanly alongside puppeteer-extra-plugin-stealth.
Install
npm install puppeteer-extra-plugin-proxyhatpuppeteer-extra and puppeteer are peer dependencies — bring your own versions.
Quick start
import puppeteer from "puppeteer-extra";
import { ProxyHatPlugin } from "puppeteer-extra-plugin-proxyhat";
// An API key auto-selects an active residential sub-user:
puppeteer.use(ProxyHatPlugin({ apiKey: process.env.PROXYHAT_API_KEY, country: "us" }));
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.goto("https://httpbin.org/ip"); // exits from a US residential IP
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();Get an API key at proxyhat.com.
Credentials
Pass them explicitly or via environment variables — options win over env:
| Option | Env var | Notes |
|---|---|---|
| apiKey | PROXYHAT_API_KEY | Auto-selects an active sub-user with remaining traffic |
| subUser | PROXYHAT_SUBUSER | Pick a specific sub-user by uuid or name (with an API key) |
| username | PROXYHAT_USERNAME | Explicit gateway proxy_username (skips the API) |
| password | PROXYHAT_PASSWORD | Explicit gateway proxy_password |
Credentials resolve lazily on first browser.launch(), so the factory stays
synchronous (the puppeteer-extra convention — no await around puppeteer.use).
A misconfiguration throws at launch, not on the first page.
Targeting
Geo and session options are flat on the plugin config:
puppeteer.use(
ProxyHatPlugin({
apiKey: process.env.PROXYHAT_API_KEY,
country: "us", // ISO code or "any" (default)
region: "california",
city: "los_angeles",
filter: "high", // AI IP-quality tier
sticky: true, // pin ONE residential IP for the whole browser ("30m" default; pass "12h" for a custom TTL)
}),
);Rotating vs sticky
Chromium takes one proxy per browser, so targeting applies to the whole browser (every page shares it):
- Rotating (default): a stable gateway username means the ProxyHat gateway hands out a fresh residential IP on every new connection.
- Sticky (
sticky: true): one sticky session id is minted once and reused across every page, so the entire browser exits from a single pinned IP for the TTL. Launch a new browser to rotate to a different sticky IP.
How it works
ProxyHatPlugin(options) returns a PuppeteerExtraPlugin. On the first launch it
resolves your gateway credentials once (via the official proxyhat SDK)
and builds the targeting-encoded gateway username with buildProxyUsername. Then:
beforeLaunchinjects--proxy-server=gate.proxyhat.com:8080into the Chromium args (unless you already set one).onPageCreatedcallspage.authenticate({ username, password })on every page, whereusernamecarries the geo/sticky targeting andpasswordis the sub-user's gateway password. This is how Chromium authenticates to an authenticated HTTP proxy — one proxy per browser, auth per page.
Advanced: a distinct proxy per page
Chromium is limited to one --proxy-server per browser, so this plugin keeps a
single upstream (lightweight, no extra processes). If you genuinely need a
different exit IP per page in the same browser, front the gateway with a
local proxy-chain forwarder per context
and point --proxy-server at 127.0.0.1:<port>. That's intentionally left out
of core — most workloads want either rotating-per-connection or one browser per
identity (launch a fresh browser to get a fresh IP), both of which this plugin
covers out of the box.
License
MIT © ProxyHat
