The One Thing Most Steel.dev Proxy Guides Get Wrong
Steel.dev is a browser API for AI agents — you create a cloud (or self-hosted) Chromium session over its API, then drive it with Playwright or Puppeteer over CDP. Most proxy guides stop at its built-in proxy (useProxy: true) and never show the setup people actually search for: attaching your own proxy so the session egresses through an IP you control.
That is the thing they get wrong. There are two different proxy concepts on a Steel session:
useProxy: true— routes through Steel's own managed proxy. You don't pick the IP.useProxy: { server: "..." }— routes through a proxy you supply. You pick the IP.
This guide is the second one: bring-your-own proxy (BYOP), using your German mobile endpoint. You get a real German mobile IP on a managed cloud browser, without running the browser yourself — and without the rotating-pool machinery, because a dedicated endpoint rotates on demand at the proxy, not per request in code. As a bonus, routing through your own endpoint means no extra per-GB proxy fee from Steel.
Before You Start
You need four values from your GermanProxy.io account:
- Host and port of your endpoint
- Username and password
You'll also need a Steel API key, plus the SDK and a driver (Playwright here):
npm install steel-sdk playwright-core
The examples use PROXY_HOST, PORT, USER and PASS as placeholders — replace them with your own. A single dedicated endpoint is enough; you do not need a rotating pool for a session. All examples use the HTTP endpoint, which is the simplest credentialed path. New to routing an agent through a proxy at all? Start with the broader AI browser-agents guide.
Step 1 — Create a Session With Your Custom Proxy
Create the session with useProxy as an object, not true. Its server field carries your German mobile endpoint as a single scheme://user:pass@host:port string. This is the BYOP path — not useProxy: true, which would use Steel's own managed proxy instead of your IP:
import Steel from "steel-sdk";
const client = new Steel({ steelAPIKey: process.env.STEEL_API_KEY });
const session = await client.sessions.create({
useProxy: {
server: "http://USER:PASS@PROXY_HOST:PORT",
},
});
console.log("Session:", session.id);
Steel accepts http://, https:// and socks5:// in the server value, so the credentials live inside that one URL — no separate auth call. If the host, port or credentials are wrong you'll see a tunnel error (ERR_TUNNEL_CONNECTION_FAILED / ERR_PROXY_CONNECTION_FAILED) rather than a silent fallback to your real IP.
Step 2 — Connect Over CDP and Drive the Session
The session runs remotely; you attach to it over CDP. Build the websocket URL from connect.steel.dev with your API key and the returned session.id, then connect Playwright — everything the browser does egresses through your German mobile endpoint:
import { chromium } from "playwright-core";
const browser = await chromium.connectOverCDP(
`wss://connect.steel.dev?apiKey=${process.env.STEEL_API_KEY}&sessionId=${session.id}`,
);
const context = browser.contexts()[0];
const page = context.pages()[0] ?? (await context.newPage());
await page.goto("https://www.example.de", { waitUntil: "domcontentloaded" });
console.log("Title:", await page.title());
await browser.close();
No launch args, no page.authenticate — the proxy was set on the session at create time, so the connection just inherits it. Prefer Puppeteer? puppeteer.connect({ browserWSEndpoint: "wss://connect.steel.dev?apiKey=…&sessionId=…" }) attaches the same way; see the Puppeteer proxy guide for that driver's quirks.
Step 3 — Verify the IP Before You Scale
Confirm the session is actually on a German mobile IP before you build anything on top of it. Point the same page at an IP-echo endpoint:
await page.goto("https://api.ipify.org?format=json", {
waitUntil: "domcontentloaded",
});
console.log("Egress IP:", await page.evaluate(() => document.body.innerText));
If it returns a datacenter address or your own, re-check the server string on useProxy — a session created with plain useProxy: true (or none at all) would run on Steel's IP, not yours. For a fuller checklist, see testing your proxy setup.
Step 4 — Check for WebRTC and DNS Leaks
A cloud browser routes HTTP through your proxy, but Chromium has two side channels that can expose the underlying address:
- WebRTC can surface an IP via ICE candidates outside the proxy tunnel — see what a WebRTC leak is.
- DNS can resolve names outside the tunnel, so the target sees a different resolver — see what a DNS leak is.
A real German mobile IP only helps if nothing else leaks past it. Verify both before you turn a single session into a fleet.
Sticky Sessions vs. Rotation
With a dedicated German endpoint you control the IP at the proxy, not in your code:
- Sticky session: one Steel session on your endpoint keeps the same German mobile IP across a multi-step task — that IP stability is what stops the target re-challenging the browser on every action.
- Rotation on demand: when you want a fresh IP, trigger rotation at the proxy and open a new session. There's no per-request IP pool to manage.
This is why a dedicated endpoint keeps the code small: no rotation list, no health-checking, no retry-on-dead-IP loop. See sticky sessions and IP rotation explained and dedicated vs shared mobile proxy.
Note the data budget: a cloud browser loads full pages with images and scripts, and a single session rendering rich pages can move several hundred MB an hour. A GermanProxy.io endpoint comes with a fair-use allowance of 20 GB/day, so size your concurrency to that rather than assuming headroom that isn't promised. We do not advertise "unlimited" traffic, because fair-use limits apply in practice and honesty is the point.
Why a Mobile IP for Steel.dev at All
A Steel session is a Chromium instance making many dependent requests as an agent works through a task, and the egress IP decides how the target treats it. Datacenter ranges — including many cloud-browser IPs — are widely distrusted, so even a well-behaved agent can hit friction. Attaching a real German mobile IP as your own proxy rides on carrier-grade NAT (CGNAT), the same shared-IP space thousands of ordinary phone users sit behind, which is why it tends to carry higher IP reputation on German platforms.
For the trade-offs against other IP types, see mobile vs residential vs datacenter proxy and what is a mobile proxy.
Scrape Responsibly
A mobile proxy improves reliability for authorized automation — it is not a tool to defeat access controls, anti-bot systems, or platform rules, and we don't position it as an "undetectable" agent. Keep your Steel sessions clean and defensible:
- Respect each site's terms and its
robots.txt; collect only public data you're permitted to use. Web scraping for public data is generally lawful in the EU, but context matters — see whether scraping is legal in Europe. - Throttle with human-reasonable delays between agent actions so you don't overload a target server.
- Collect only what you need, and handle any personal data in line with the GDPR.
- Be honest about who you are — don't impersonate a service or misuse a target's security mechanisms.
[!IMPORTANT]
GermanProxy.io is an EU-based provider with a full imprint, clear acceptable-use rules, and a real abuse-reporting process. The service is IT routing — a host, port and credentials — not hardware you operate, and not framed as anonymity. Whether mobile proxies are lawful to use: are mobile proxies legal.
FAQ
How do I add a custom proxy to a Steel.dev session?
Pass useProxy as an object to client.sessions.create with a server field: useProxy: { server: "http://USER:PASS@PROXY_HOST:PORT" }. The session then egresses through your endpoint. Connect Playwright or Puppeteer over CDP using wss://connect.steel.dev with your API key and the session id.
What's the difference between BYOP and Steel's built-in proxy?
useProxy: true selects Steel's own managed proxy. Passing useProxy as an object with a server routes the session through a proxy you supply — your German mobile endpoint — so you control the outbound IP and pay no extra per-GB proxy fee to Steel.
How do I connect Playwright or Puppeteer to a Steel session?
After client.sessions.create returns, connect over CDP to wss://connect.steel.dev?apiKey=STEEL_API_KEY&sessionId=SESSION_ID with chromium.connectOverCDP (Playwright) or puppeteer.connect. Everything the browser does then egresses through the proxy you set at create time.
Which proxy schemes does Steel.dev accept for a custom proxy?
Steel accepts http, https and socks5 in the server value — scheme://user:pass@host:port. Your GermanProxy.io endpoint gives you HTTP/SOCKS5 (plus OpenVPN), so use the HTTP endpoint for the simplest credentialed setup. Background: HTTP vs SOCKS5 proxies.
Should I check for WebRTC and DNS leaks on Steel.dev?
Yes. A cloud browser can still expose the underlying address through WebRTC or resolve DNS outside the tunnel — see what a WebRTC leak is and what a DNS leak is. Have the session open an IP-echo page to confirm a German mobile IP, then run a leak test before you rely on the setup.
Do I need a rotating pool for Steel.dev sessions?
No. A single dedicated German mobile endpoint is usually the better fit. A stateful, multi-step session needs a stable IP (sticky session) so it is not re-challenged on every action; rotate on demand at the proxy between tasks, not mid-task. See sticky sessions and IP rotation explained.
Related guides
- Hyperbrowser Proxy Setup: Sessions on German Mobile IPs
- Browserbase Proxy Setup: Sessions on German Mobile IPs
- Stagehand Proxy Setup: Route via German Mobile IPs
- Browserless Proxy Setup: Route via German Mobile IPs
CTA
Run your Steel.dev sessions on real German mobile IPs. Get a German mobile proxy — HTTP/SOCKS5/OpenVPN, sticky sessions, on-demand rotation, fair-use 20 GB/day, from a transparent EU provider. Browse the plans to get started. New to the topic? Start with the AI-agents use case or what is a mobile proxy.
Get a German mobile proxy: Real 4G/5G IPs from Germany, fair-use 20 GB/day — browse German mobile proxy plans or get a dedicated proxy on the Blue network.