stagehand-proxyhat
v0.1.1
Published
Route Stagehand's local browser through ProxyHat residential proxies — a pinned sticky IP per agent session, geo-targeting, and rotating IPs.
Downloads
271
Maintainers
Readme
stagehand-proxyhat
Route Stagehand's local browser through ProxyHat residential proxies — a pinned sticky IP per agent session, geo-targeting, and rotating IPs.
[!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
Stagehand drives an AI agent over a browser (Playwright under the hood). When you run it locally (env: "LOCAL"), that browser goes out from your own datacenter IP — which gets your agent blocked, CAPTCHA'd, and rate-limited. This package plugs ProxyHat's residential IPs (50M+ across 148+ countries) into Stagehand's local browser through its first-class proxy option, and maps each Stagehand instance to one pinned residential IP for its whole agent session — mimicking a real user. No boilerplate.
Install
npm install stagehand-proxyhat@browserbasehq/stagehand is a peer dependency — bring your own version (>=2).
Quick start
import { Stagehand } from "@browserbasehq/stagehand";
import { proxyhatStagehandConfig } from "stagehand-proxyhat";
// An API key auto-selects an active residential sub-user. `env` defaults to
// "LOCAL"; your own Stagehand config (model, systemPrompt, …) is preserved.
const config = await proxyhatStagehandConfig(
{ apiKey: process.env.PROXYHAT_API_KEY, targeting: { country: "us" } },
{ model: "openai/gpt-4o" },
);
const stagehand = new Stagehand(config);
await stagehand.init();
const page = stagehand.context.pages()[0];
await page.goto("https://httpbin.org/ip"); // exits from a US residential IPGet an API key at proxyhat.com.
Where the proxy lands
Stagehand's local browser reads its proxy from localBrowserLaunchOptions.proxy (a Playwright-shaped { server, username, password, bypass }). proxyhatStagehandConfig returns a full Stagehand constructor config (v3 V3Options, formerly ConstructorParams) with that field filled in; proxyhatProxy returns just the proxy object if you'd rather set it yourself.
The proxy only applies to
env: "LOCAL". Inenv: "BROWSERBASE"the browser runs in Browserbase's cloud and proxies are configured there instead —proxyhatStagehandConfigpreserves whateverenvyou pass but the proxy field is only honoured locally.
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 |
Targeting
const config = await proxyhatStagehandConfig({
apiKey: process.env.PROXYHAT_API_KEY,
protocol: "http", // or "socks5"
targeting: {
country: "us", // ISO code or "any" (default)
region: "california",
city: "new_york",
filter: "high", // AI IP-quality tier
},
stickyTtl: "30m", // sticky-session lifetime (default "30m")
});Sticky IP per agent session
By default this package pins each Stagehand instance to one ProxyHat residential IP: a fresh sticky id is minted per call, so every request the agent makes during its session keeps that same IP, like a real user. Close the browser and the IP is dropped. Build a second Stagehand instance and it gets its own distinct pinned IP.
Want a fresh IP on every request instead? Turn stickiness off — the gateway rotates the exit IP per connection:
const config = await proxyhatStagehandConfig({ apiKey, sticky: false });Build the proxy object yourself
Already have a Stagehand config? Use proxyhatProxy for just the proxy object and drop it into localBrowserLaunchOptions.proxy:
import { Stagehand } from "@browserbasehq/stagehand";
import { proxyhatProxy } from "stagehand-proxyhat";
const proxy = await proxyhatProxy({ apiKey: process.env.PROXYHAT_API_KEY, targeting: { country: "us" } });
const stagehand = new Stagehand({
env: "LOCAL",
model: "openai/gpt-4o",
localBrowserLaunchOptions: { headless: false, proxy },
});
await stagehand.init();Fully offline and synchronous once you have credentials:
import { buildStagehandProxy, resolveCredentials } from "stagehand-proxyhat";
const credentials = await resolveCredentials({ apiKey: process.env.PROXYHAT_API_KEY });
const proxy = buildStagehandProxy(credentials, { targeting: { country: "us" } });
// -> { server: "http://gate.proxyhat.com:8080", username: "…-country-us-sid-…-ttl-30m", password: "…" }How it works
proxyhatProxy (and proxyhatStagehandConfig) resolves your gateway credentials once (via the official proxyhat SDK), then builds the proxy object Stagehand's local browser expects: server points at the ProxyHat gateway (gate.proxyhat.com:8080 for HTTP, :1080 for SOCKS5) and username carries the targeting grammar. With stickiness on it mints a sid/ttl so the session keeps one pinned IP; with sticky: false it omits the sid so the gateway hands out a fresh residential IP per connection.
License
MIT © ProxyHat
