# /integrations - Proxies.sx Pool Gateway in agent frameworks > Machine-readable companion to https://agents.proxies.sx/integrations/ . One section per framework, each with the same runnable snippet as its HTML page. Canonical gateway contract: https://agents.proxies.sx/pool/skill.md (wins on any disagreement; the live API wins over that). ## Common facts - Gateway: `gw.proxies.sx:7000` (HTTP) / `gw.proxies.sx:7001` (SOCKS5). Chromium-based tools need the HTTP port (no SOCKS5 auth). - Username DSL: `psx_--[-rot-][-sid-]` - `pool`: `peer` (~127 countries) | `mbl` (carrier modems: US GB FR NL PL GE - GE is Georgia) | `any` | `best`. Germany = `peer-de`. - `-sid-` (1-64 chars, no `-`) is REQUIRED for `sticky` and `auto*`; without it every connection is a new session. Sticky pins the device, not the IP. - Unknown tokens are dropped silently. There is no `-session-` token. - Credentials: `curl https://api.proxies.sx/v1/gateway/credentials -H "X-API-Key: psx_..."` -> `username` (= `psx_`) + connect strings. Proxy password is set in the portal (https://client.proxies.sx/api-keys), separate from the login password. - Price: $4/GB, $2.40/GB at 250 GB+, duration free. Sign up: https://client.proxies.sx/signup - Replace `ACCOUNT_ID` and `PROXY_PASSWORD` in every snippet. ## browser-use Page: https://agents.proxies.sx/integrations/browser-use/ browser-use is a Python library that lets an LLM drive a real Chromium browser through Playwright: you give an Agent a task in plain English and it clicks, types and reads pages until the task is done. Rotation: sticky, one -sid- per Agent run. A browser task is a session: cookies, logins and carts only make sense if every request in the run leaves from the same device. Generate a session id per run and pin it with -rot-sticky. Use auto10 only for stateless crawls. ```python # pip install browser-use (Python 3.11+, then: playwright install chromium) import asyncio, uuid from browser_use import Agent, BrowserSession, BrowserProfile, ChatOpenAI sid = uuid.uuid4().hex[:12] # one session id per run proxy = { "server": "http://gw.proxies.sx:7000", "username": f"psx_ACCOUNT_ID-peer-us-rot-sticky-sid-{sid}", # sticky US exit for the whole task "password": "PROXY_PASSWORD", } async def main(): session = BrowserSession(browser_profile=BrowserProfile(proxy=proxy)) agent = Agent( task="Open https://api.ipify.org?format=json and tell me the ip field", llm=ChatOpenAI(model="gpt-4o-mini"), browser_session=session, ) print(await agent.run()) asyncio.run(main()) ``` Note: browser-use 0.2+ takes the proxy on BrowserProfile; older releases used BrowserConfig(proxy=...). Both accept the same server/username/password dict. ## Playwright Page: https://agents.proxies.sx/integrations/playwright/ Playwright is Microsoft's browser-automation library for Chromium, Firefox and WebKit, with first-class proxy support at launch time and per-context. Rotation: sticky per browser context; ondemand for one-shot fetches. Pin one session id per context so a login survives navigation. If you open many contexts in parallel, give each its own -sid- and they each get their own device. ```node // npm i playwright (then: npx playwright install chromium) import { chromium } from "playwright"; import { randomUUID } from "node:crypto"; const sid = randomUUID().slice(0, 12); // one session id per context const browser = await chromium.launch({ proxy: { server: "http://gw.proxies.sx:7000", username: `psx_ACCOUNT_ID-peer-gb-rot-sticky-sid-${sid}`, // sticky UK exit password: "PROXY_PASSWORD", }, }); const page = await browser.newPage(); await page.goto("https://api.ipify.org?format=json"); console.log(await page.textContent("body")); await browser.close(); ``` Note: Python Playwright is identical: chromium.launch(proxy={"server": ..., "username": ..., "password": ...}). SOCKS5 with auth is not supported by Chromium's proxy stack, so use the HTTP port :7000 here. ## OpenAI Agents SDK Page: https://agents.proxies.sx/integrations/openai-agents-sdk/ The OpenAI Agents SDK is OpenAI's Python framework for agents with tools, handoffs and guardrails. The proxy goes into whichever tool touches the web; the model calls stay on OpenAI's API. Rotation: sticky per Runner.run for multi-page research; ondemand for independent lookups. Create the session id once per run so every fetch the agent makes during that run shares one exit; a fresh id on the next run gives a fresh device. ```python # pip install openai-agents httpx import uuid, httpx from agents import Agent, Runner, function_tool SID = uuid.uuid4().hex[:12] # one session id per run PROXY = f"http://psx_ACCOUNT_ID-peer-de-rot-sticky-sid-{SID}:PROXY_PASSWORD@gw.proxies.sx:7000" @function_tool def fetch_page(url: str) -> str: """Fetch a URL through a German residential/mobile exit.""" with httpx.Client(proxy=PROXY, timeout=30) as c: return c.get(url).text[:4000] agent = Agent(name="scout", instructions="Use fetch_page for any web lookup.", tools=[fetch_page]) print(Runner.run_sync(agent, "What IP does https://api.ipify.org report?").final_output) ``` Note: Germany has no carrier modem, so the pool is peer-de; mbl-de always fails. ## Vercel AI SDK Page: https://agents.proxies.sx/integrations/vercel-ai-sdk/ The Vercel AI SDK (the ai package) is a TypeScript toolkit for LLM apps with a unified tool-calling API. Node's built-in fetch ignores proxy env vars, so route tool fetches through an undici ProxyAgent. Rotation: sticky per generateText call; ondemand when every tool call is independent. Build the dispatcher once per request with a fresh session id and reuse it for every tool call in that request. ```node // npm i ai @ai-sdk/openai undici zod import { generateText, tool, stepCountIs } from "ai"; import { openai } from "@ai-sdk/openai"; import { ProxyAgent, fetch as proxiedFetch } from "undici"; import { randomUUID } from "node:crypto"; import { z } from "zod"; const sid = randomUUID().slice(0, 12); // one session id per request const username = `psx_ACCOUNT_ID-peer-us-rot-sticky-sid-${sid}`; const dispatcher = new ProxyAgent({ uri: "http://gw.proxies.sx:7000", token: "Basic " + Buffer.from(`${username}:PROXY_PASSWORD`).toString("base64"), }); const { text } = await generateText({ model: openai("gpt-4o-mini"), prompt: "What IP does https://api.ipify.org?format=json report?", stopWhen: stepCountIs(3), tools: { fetchPage: tool({ description: "Fetch a URL through a US residential/mobile exit", inputSchema: z.object({ url: z.string().url() }), execute: async ({ url }) => (await proxiedFetch(url, { dispatcher })).text(), }), }, }); console.log(text); ``` Note: AI SDK 5 shown (inputSchema, stopWhen). On AI SDK 4 the tool field is parameters and the loop option is maxSteps. ## n8n Page: https://agents.proxies.sx/integrations/n8n/ n8n is a source-available workflow automation tool. Its HTTP Request node has a Proxy option that takes a full proxy URL, so the whole username DSL fits in one expression. Rotation: sticky per execution: -sid-{{ $execution.id }}. The execution id is unique per workflow run and stable across every node in it, so all HTTP Request nodes in one run share one exit. For a stateless poll use -rot-ondemand and drop the sid. ```json { "nodes": [ { "name": "Fetch via Proxies.sx", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.2, "position": [0, 0], "parameters": { "url": "https://api.ipify.org?format=json", "options": { "proxy": "=http://psx_ACCOUNT_ID-peer-fr-rot-sticky-sid-{{ $execution.id }}:PROXY_PASSWORD@gw.proxies.sx:7000" } } } ], "connections": {} } ``` Note: Paste the JSON into the n8n canvas, or set Options > Proxy on any HTTP Request node by hand. The leading = marks an expression. Keep credentials in an n8n credential or environment variable rather than inline. ## Stagehand Page: https://agents.proxies.sx/integrations/stagehand/ Stagehand (by Browserbase) adds act, extract and observe primitives on top of Playwright so an LLM can operate pages with natural-language instructions. Its local launch cannot take an authenticated proxy yet, so the sample routes a Browserbase session through the gateway with an external proxy. Rotation: sticky per Stagehand instance. One Stagehand instance is one browser session; give it one session id at init and every act/extract in it shares the exit. ```node // npm i @browserbasehq/stagehand zod // Stagehand's local launch does not support authenticated proxies (docs.stagehand.dev/configuration/browser), // so route the Browserbase session through the gateway with an external proxy. import { Stagehand } from "@browserbasehq/stagehand"; import { randomUUID } from "node:crypto"; import { z } from "zod"; const sid = randomUUID().slice(0, 12); // one session id per instance const stagehand = new Stagehand({ env: "BROWSERBASE", apiKey: process.env.BROWSERBASE_API_KEY, projectId: process.env.BROWSERBASE_PROJECT_ID, browserbaseSessionCreateParams: { projectId: process.env.BROWSERBASE_PROJECT_ID, proxies: [{ type: "external", server: "http://gw.proxies.sx:7000", username: `psx_ACCOUNT_ID-peer-us-rot-sticky-sid-${sid}`, password: "PROXY_PASSWORD", }], }, }); await stagehand.init(); const page = stagehand.context.pages()[0]; await page.goto("https://api.ipify.org?format=json"); const { ip } = await stagehand.extract("the ip field", z.object({ ip: z.string() })); console.log(ip); await stagehand.close(); ``` Note: With env: "BROWSERBASE" the proxy is configured on the Browserbase session instead; the DSL string is the same. ## LangChain Page: https://agents.proxies.sx/integrations/langchain/ LangChain is the most widely used LLM application framework. A proxy belongs in the tool that fetches, so wrap httpx in a @tool and hand it to a ReAct agent. Rotation: sticky per agent invocation. Generate the session id when you build the tool for a run. Reusing one module-level id across days would pin every run to the same device; a per-run id keeps runs isolated. ```python # pip install langchain-core langchain-openai langgraph httpx import uuid, httpx from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent SID = uuid.uuid4().hex[:12] # one session id per run PROXY = f"http://psx_ACCOUNT_ID-peer-gb-rot-sticky-sid-{SID}:PROXY_PASSWORD@gw.proxies.sx:7000" @tool def fetch_page(url: str) -> str: """Fetch a URL through a UK residential/mobile exit.""" return httpx.get(url, proxy=PROXY, timeout=30).text[:4000] agent = create_react_agent(ChatOpenAI(model="gpt-4o-mini"), tools=[fetch_page]) result = agent.invoke({"messages": [("user", "What IP does https://api.ipify.org report?")]}) print(result["messages"][-1].content) ``` Note: For document loaders (WebBaseLoader, AsyncHtmlLoader) pass requests_kwargs={"proxies": {"http": PROXY, "https": PROXY}} instead. ## CrewAI Page: https://agents.proxies.sx/integrations/crewai/ CrewAI orchestrates role-playing agents into crews that share tasks. Tools are plain Python functions decorated with @tool, so the proxy lives inside the tool body. Rotation: sticky per crew kickoff. All agents in one crew usually work one job, so they can share one session id; if two agents must look like two visitors, build two tools with two ids. ```python # pip install crewai httpx import uuid, httpx from crewai import Agent, Task, Crew from crewai.tools import tool SID = uuid.uuid4().hex[:12] # one session id per kickoff PROXY = f"http://psx_ACCOUNT_ID-peer-us-rot-sticky-sid-{SID}:PROXY_PASSWORD@gw.proxies.sx:7000" @tool("fetch_page") def fetch_page(url: str) -> str: """Fetch a URL through a US residential/mobile exit.""" return httpx.get(url, proxy=PROXY, timeout=30).text[:4000] scout = Agent(role="Scout", goal="Read web pages through the proxy", backstory="Careful and literal.", tools=[fetch_page]) task = Task(description="What IP does https://api.ipify.org report?", expected_output="An IPv4 address", agent=scout) print(Crew(agents=[scout], tasks=[task]).kickoff()) ``` Note: CrewAI reads OPENAI_API_KEY from the environment for the LLM; the proxy only affects fetch_page. ## Make and Zapier Page: https://agents.proxies.sx/integrations/make-zapier/ Make and Zapier are no-code automation platforms. Neither the Make HTTP module nor Zapier's Webhooks step exposes an outbound proxy setting, so the pattern is different: use them to drive the Proxies.sx REST API and hand the resulting proxy URL to the step that does the fetching (your own worker, a Code step, or a scraper that accepts a proxy URL). Rotation: ondemand, or sticky keyed on the scenario/zap run id. Build the username with the run id as the session id ({{execution_id}} in Make, the zap run id in Zapier) so every step of one run shares one exit. ```bash # Step 1 - HTTP module / Webhooks step: fetch your ready-made credentials (once) curl https://api.proxies.sx/v1/gateway/credentials -H "X-API-Key: psx_YOUR_API_KEY" # -> { "username": "psx_ACCOUNT_ID", "httpProxy": "http://psx_ACCOUNT_ID:PASS@gw.proxies.sx:7000", ... } # Step 2 - a Text/Set-variable step builds the per-run proxy URL from the DSL: # http://psx_ACCOUNT_ID-peer-us-rot-sticky-sid-{{execution_id}}:PROXY_PASSWORD@gw.proxies.sx:7000 # Step 3 - the step that actually fetches uses that URL, e.g. a worker you host: curl -x "http://psx_ACCOUNT_ID-peer-us-rot-sticky-sid-RUN_ID:PROXY_PASSWORD@gw.proxies.sx:7000" https://api.ipify.org?format=json ``` Note: The X-API-Key header is what every Proxies.sx REST call needs; the gateway itself only ever sees the username/password pair.