How to Configure Stat Proxies with Kernel Browser (2026 Guide)

By Nicholas St. Germain —

Kernel is browser infrastructure for agents. You call an API, you get a Chromium session running in Kernel's cloud, and you drive it with Playwright over CDP, with computer use, or through WebDriver BiDi. It ships with managed proxies of its own, and it also lets you bring your own: a custom proxy is a saved configuration that Kernel attaches to any browser session by ID.

That bring-your-own path is what this guide covers. You point a Kernel custom proxy at a static ISP proxy from Stat, attach it to a browser session, and every request that session makes leaves from an IP you own for as long as you keep paying for it, not from a shared pool and not from Kernel's datacenter range.

The whole configuration is four fields. The rest of this guide is about getting those four fields right, proving they worked, and knowing what to do when they didn't.

Why bring your own proxy to Kernel

Kernel already offers five proxy types: datacenter, ISP, residential, mobile, and custom. Its managed ISP proxies give you a static exit IP that persists across sessions, which covers a lot of ground. So be clear-eyed about when a custom proxy is the better answer:

  • You need the same IP across more than one provider. If your agent stack spans Kernel, a local Playwright runner, and a Python worker that calls an API directly, a proxy you own is the only way all three exit from one address. A managed proxy is scoped to the platform that manages it.
  • Kernel's upstream blocks your destination. Kernel's own documentation is explicit that some destination categories, including government, banking, and payment domains, are blocked by its upstream network providers and will fail at the proxy layer, and it points at a custom proxy as the fix. If your workflow touches those, this is not an optimization, it is the only route.
  • Bandwidth economics. Screenshot-heavy agent loops and vision models move a lot of data. Stat bills flat per IP per month with unmetered bandwidth, so a run that renders ten thousand pages costs the same as one that renders ten.
  • You want to replace one burned IP without touching anything else. Stat exposes a management API that swaps a single IP on an order and leaves the rest alone.
  • Compliance. Some teams need to name the network their traffic leaves from, and point at an invoice for it.

If none of those apply, Kernel's managed ISP proxy is genuinely fine and it is one line of code. Use the simplest thing that works.

What you need before you start

  1. A Stat order with at least one proxy on it. Any ISP, captcha, events, or fiber plan works. They all speak HTTP and HTTPS with username and password auth on port 3128.
  2. A Kernel account and an API key. New accounts land on an onboarding screen with a generate api key button, and the key also lives under org settings, api keys.
  3. The Kernel SDK, if you plan to script it rather than click through the dashboard.

The Kernel onboarding screen, showing the generate api key button and a first browser launch snippet

# Node
npm install @onkernel/sdk playwright

# Python
pip install kernel playwright

Both SDKs read KERNEL_API_KEY from the environment by default, so new Kernel() and Kernel() need no arguments once it is exported.

Step 1: Get your Stat credentials

Open your order in the Stat dashboard and look at the Connection panel. It carries everything you need: the username, the password, and the IP list rendered in whichever format you pick from the dropdown.

The Connection panel in the Stat Proxies dashboard, showing username, password, and a list of six proxies in IP:PORT:USER:PASS format

Two things worth noting before you move on:

  • The username and password are shared across every IP on the order. Ten proxies on one order means ten hosts and one credential pair, not ten credential pairs.
  • The port is always 3128. It is the same on every product and every server.

Copy one line. That single line is the whole configuration.

Step 2: Map the credential line onto Kernel's fields

Kernel's custom proxy config takes host, port, username, and password. A Stat credential line in IP:PORT:USER:PASS order is those four values, in that order, separated by colons.

Take the line 192.0.2.6:3128:sub_1rqjp3jb4g9i6pkhdwmkpjob:stat261 and it splits like this:

Segment Kernel field
192.0.2.6 config.host
3128 config.port
sub_1rqjp3jb4g9i6pkhdwmkpjob config.username
stat261 config.password

The one field that is not in the credential line, and the one people get wrong, is protocol.

Kernel's protocol describes the hop between the Kernel browser and your proxy, and it defaults to https, which means Kernel expects to open a TLS connection to the proxy itself. Stat's endpoint on port 3128 is a plain HTTP proxy endpoint, so set protocol to http.

This does not weaken anything about your traffic. Requests to https:// sites are still tunnelled through the proxy with CONNECT and stay encrypted end to end between the browser and the destination. The only thing protocol controls is whether the short hop from Kernel's browser VM to the proxy is itself wrapped in TLS.

Leave http selected and this works. Leave the default https selected and you get a handshake failure that looks, unhelpfully, like the proxy is down.

Step 3: Create the proxy in Kernel

You can do this in the dashboard or in code. The dashboard version is easier to see once, and the code version is what you will actually ship, so here is both.

In the dashboard

Open proxies in the left sidebar. On a fresh project it is empty, with a create proxy button in the middle.

The Kernel dashboard proxies page in its empty state, with a create proxy button

Kernel asks which type first. The four managed types sit at the top; custom is the one at the bottom.

Kernel's create proxy dialog asking you to choose a proxy type: datacenter, isp, residential, mobile, or custom

Now the form with the four fields, plus the protocol dropdown discussed above.

Kernel's custom proxy form with fields for proxy name, protocol, host, port, username, password, and an optional CA bundle

Fill it in like this:

Field Value Notes
proxy name stat-isp-agent-01 Free text. Name it after the agent that will use it, not after the IP.
protocol HTTP Change this from the HTTPS default. See step 2.
host 192.0.2.6 One IP from your Stat list.
port 3128 Always 3128.
username sub_1rqjp... From the Connection panel.
password stat261 From the Connection panel. Kernel requires 5 characters or more.
ca bundle empty Only for proxies that terminate and re-sign TLS. Stat does not, so skip it.

Hit create proxy and you get a proxy ID back. That ID is what you attach to browser sessions.

In code

The same thing through the SDK, which is what you want the moment you have more than one IP:

import Kernel from '@onkernel/sdk';

const kernel = new Kernel(); // reads KERNEL_API_KEY

const proxy = await kernel.proxies.create({
  type: 'custom',
  name: 'stat-isp-agent-01',
  protocol: 'http', // not the 'https' default: port 3128 is a plain HTTP proxy
  config: {
    host: process.env.STAT_PROXY_IP,       // 192.0.2.6
    port: 3128,
    username: process.env.STAT_PROXY_USER, // sub_1rqjp3jb4g9i6pkhdwmkpjob
    password: process.env.STAT_PROXY_PASS,
  },
});

console.log(proxy.id, proxy.status);
import os
from kernel import Kernel

kernel = Kernel()  # reads KERNEL_API_KEY

proxy = kernel.proxies.create(
    type="custom",
    name="stat-isp-agent-01",
    protocol="http",
    config={
        "host": os.environ["STAT_PROXY_IP"],
        "port": 3128,
        "username": os.environ["STAT_PROXY_USER"],
        "password": os.environ["STAT_PROXY_PASS"],
    },
)

print(proxy.id, proxy.status)

The password is write-only. Kernel's API returns has_password: true rather than the value, which matters later when you rotate credentials.

Before you attach it to anything, run a health check. It validates credentials and connectivity, and it takes an optional URL so you can test the destination you actually care about:

await kernel.proxies.check(proxy.id, { url: 'https://ipinfo.io/json' });

For a static ISP proxy the exit IP does not move, so a successful check against a real URL tells you something durable: the same session will reach the same target from the same address later.

Step 4: Attach the proxy to a browser session

One parameter, proxy_id, at browser creation:

import Kernel from '@onkernel/sdk';
import { chromium } from 'playwright';

const kernel = new Kernel();

const kernelBrowser = await kernel.browsers.create({
  proxy_id: proxy.id,
});

const browser = await chromium.connectOverCDP(kernelBrowser.cdp_ws_url);
const context = browser.contexts()[0];
const page = context.pages()[0];

await page.goto('https://ipinfo.io/json');
console.log(await page.evaluate(() => document.body.innerText));

await browser.close();
import asyncio
from kernel import Kernel
from playwright.async_api import async_playwright

kernel = Kernel()

async def main():
    kernel_browser = kernel.browsers.create(proxy_id=proxy.id)

    async with async_playwright() as pw:
        browser = await pw.chromium.connect_over_cdp(kernel_browser.cdp_ws_url)
        context = browser.contexts[0]
        page = context.pages[0]

        await page.goto("https://ipinfo.io/json")
        print(await page.evaluate("document.body.innerText"))

        await browser.close()

asyncio.run(main())

Nothing else in your Playwright code changes. No launch flags, no http_credentials, no proxy-auth extension. Kernel runs an Envoy sidecar next to Chromium in the browser VM and forwards through your proxy from there, which is also why the usual Playwright proxy authentication headaches do not show up here.

Two behaviours worth knowing:

  • Stealth browsers get a managed proxy by default. If you want anti-detection plus your own IP, pass both: { stealth: true, proxy_id: proxy.id } keeps Kernel's anti-detection configuration while routing through you. The separate disable_default_proxy flag is for stealth browsers with no proxy at all, and it cannot be combined with proxy_id.
  • You can hot-swap the proxy on a running session. kernel.browsers.update(sessionId, { proxy_id: otherProxy.id }) applies in about two to three seconds, and passing an empty string routes the session direct. The network drops briefly during the swap, so in-flight requests can fail.

Step 5: Verify it end to end

Check both sides. The browser tells you what the destination sees, and your Stat dashboard tells you the traffic really went through your IP rather than around it.

From inside the session, the ipinfo.io response should show your Stat IP and a residential ISP as the org, not a cloud provider:

{
  "ip": "192.0.2.6",
  "city": "Ashburn",
  "region": "Virginia",
  "country": "US",
  "org": "AS6079 RCN"
}

If the ip field is anything other than the host you configured, the proxy is not attached. Go back and confirm proxy_id was passed to browsers.create and not just created and left sitting there.

From the Stat side, open the order and look at the Usage panel. Requests and bandwidth should climb while your agent runs.

The Usage panel in the Stat Proxies dashboard, showing a rising daily request count totalling 19,490 requests and 6,114 MB transferred

Top domains is the better check of the two, because it tells you what went through the proxy. A browser agent renders a full page, so you should see the target site plus its CDN and asset hosts, not one lonely API domain:

The Top domains panel in the Stat Proxies dashboard listing app.target-site.com, cdn.target-site.com, ipinfo.io, fonts.googleapis.com and api.target-site.com with request counts

If the target site appears but its CDN does not, something is routing around the proxy. Check your bypass host rules.

Running one IP per agent

The reason to use static ISP proxies with browser agents at all is that a long, logged-in, multi-step run keeps one identity from first click to last. That means one Stat IP per concurrent agent, and one Kernel proxy configuration per IP.

const STAT_IPS = ['192.0.2.6', '192.0.2.7', '192.0.2.18', '192.0.2.42'];

// Create once at startup, store the IDs, reuse them forever.
const proxies = await Promise.all(
  STAT_IPS.map((host, i) =>
    kernel.proxies.create({
      type: 'custom',
      name: `stat-isp-agent-${String(i + 1).padStart(2, '0')}`,
      protocol: 'http',
      config: {
        host,
        port: 3128,
        username: process.env.STAT_PROXY_USER,
        password: process.env.STAT_PROXY_PASS,
      },
    }),
  ),
);

// Then pin each agent to its own proxy for the life of the workflow.
const browser = await kernel.browsers.create({ proxy_id: proxies[agentIndex].id });

Create these once and persist the IDs. Kernel garbage-collects proxy configurations that have gone 14 days without use once an organization holds more than 100 of them, though anything attached to a session, pool, or managed auth connection is retained.

If you run browser pools for instant browser acquisition, note that a hot-swapped proxy resets to the pool's default when the browser is released.

Bypass hosts

Kernel can route specific hostnames around the proxy and out through its own direct egress. This is worth doing for anything that does not need to carry your IP identity:

const proxy = await kernel.proxies.create({
  type: 'custom',
  name: 'stat-isp-agent-01',
  protocol: 'http',
  config: { host, port: 3128, username, password },
  bypass_hosts: ['localhost', '*.internal.example.com'],
});

Exact hostnames and wildcard subdomains are supported, up to 100 entries. Ports, paths, schemes, and bare IP addresses are not. Be conservative here: sending a site's assets direct while its HTML goes through the proxy is exactly the kind of split that fingerprinting picks up on.

Replacing a burned IP

When one IP starts getting challenged, swap it at the source rather than rebuilding your whole setup. Stat's API replaces a single IP on an order and leaves the username, password, port, and every other IP untouched:

curl -X POST "https://dashboard.statproxies.com/api/v2/order/replace/{order_id}" \
  -H "Authorization: Bearer {your_api_key}" \
  -H "Content-Type: application/json" \
  -d '{"ip": "192.0.2.6"}'
{
  "response": "success",
  "details": {
    "old_ip": "192.0.2.6",
    "new_ip": "192.0.2.42",
    "new_proxy": "192.0.2.42:3128:sub_1rqjp3jb4g9i6pkhdwmkpjob:stat261"
  }
}

Then update the Kernel side. Kernel's proxy update call is documented for renaming, so treat host, port, and credentials on an existing configuration as fixed: create a new custom proxy with the new host, point your agent at the new ID, and delete the old configuration once nothing references it. Deleting a proxy immediately reconfigures any browser still attached to it to route direct, so delete last, not first.

Replacement is rate limited to one IP per order per 60 seconds. The full endpoint reference is in API_ORDER_DOCS.md and the order API documentation.

Troubleshooting

407 Proxy Authentication Required

The username or password is wrong, or the password was rotated in the Stat dashboard after the Kernel configuration was created. Because Kernel stores the password write-only, you cannot inspect what it has: create a fresh proxy configuration with the current credentials and swap to it. Our 407 troubleshooting guide covers the other causes.

Handshake or connection errors that look like the proxy is down

Nine times out of ten this is protocol left on the https default against port 3128. Set it to http and try again. Kernel's proxy health check surfaces this quickly, which is why it is worth running before you attach the proxy to anything.

The session shows a datacenter IP

Either proxy_id never made it into browsers.create, or you are on a stealth browser using Kernel's default managed proxy. Pass proxy_id explicitly. Remember disable_default_proxy and proxy_id are mutually exclusive.

Requests to one specific site fail while everything else works

Check whether that host matches a bypass_hosts entry, and remember wildcards only match subdomains. If the site is a bank, a payment processor, or a government domain, this is the case where a custom proxy is the fix rather than the problem, since Kernel's managed pools block those categories upstream.

It works in cURL but not in Kernel

Kernel connects to your proxy from its own cloud infrastructure, not from your laptop. Stat proxies authenticate by username and password from any source IP, so there is no allowlist to update, but it is worth confirming you tested the same IP and the same credentials. Start with our cURL proxy testing guide.

The proxy works but pages still get blocked

That is a fingerprinting problem, not an IP problem. Turn on Kernel's stealth mode alongside your proxy_id, and read why AI agents get blocked by Cloudflare for what else the checks look at.

What Stat does not do

Worth stating plainly so you do not design around features that are not there:

  • No SOCKS5. HTTP and HTTPS only, which is all Kernel's custom proxy accepts anyway.
  • No rotation. Stat IPs are static and dedicated. That is the point of pairing them with agent sessions, but if you need a new IP per request, use Kernel's managed residential or mobile pools instead.
  • No IP allowlist or token auth on the proxy connection. Username and password only. The Bearer token API manages orders and IPs, it does not authenticate proxy traffic.
  • US locations. If you need non-US exit geography, that is a Kernel managed proxy job.

FAQ

Does Kernel support username and password proxy authentication?

Yes. A custom proxy configuration takes username and password alongside host and port, and Kernel's Envoy sidecar handles the Proxy-Authorization header for the browser. Your Playwright code needs no credential handling of its own.

Should protocol be http or https for Stat Proxies?

Set it to http. Kernel's protocol field describes the connection between the Kernel browser and your proxy, and it defaults to https, which expects TLS on that hop. Stat's endpoint on port 3128 is a plain HTTP proxy. Traffic to https:// destinations is still tunnelled with CONNECT and stays encrypted end to end regardless of this setting.

Do I need a separate Kernel proxy configuration for every Stat IP?

Yes. A Kernel custom proxy points at one host and port, so ten Stat IPs means ten configurations. They all share the same username and password, so it is a short loop at startup. Create them once, store the IDs, and reuse them.

Can I change the IP on an existing Kernel custom proxy?

Treat host, port, and credentials as fixed once created. Kernel's proxy update call is documented for renaming a configuration. To move to a new IP, create a new custom proxy, point your sessions at the new ID, then delete the old one. Delete last, because deleting a proxy immediately routes any attached browser direct.

Will the same IP be used across multiple Kernel sessions?

Yes. Stat ISP proxies are static and dedicated, so every Kernel session attached to that proxy configuration exits from the same address, today and next month. That persistence is the whole reason to use them for logged-in agent workflows.

Is bandwidth metered?

No. Stat bills flat per IP per month with unlimited bandwidth, which is why it suits screenshot-heavy and vision-model agent loops where per-GB pricing gets expensive fast. Our flat rate versus per GB breakeven math works through where the crossover sits.

Do I still need Kernel's stealth mode with a custom proxy?

Usually yes. A clean residential IP solves IP reputation; it does not solve browser fingerprinting, TLS fingerprinting, or behavioural checks. Passing stealth: true alongside proxy_id keeps Kernel's anti-detection configuration and routes through your IP.

What is the CA bundle field for?

Only for proxies that terminate and re-sign upstream TLS, which is common with corporate inspection proxies. Stat does not intercept TLS, so leave it empty. If you do need it, the bundle has to be supplied at browser creation and cannot be hot-swapped onto a running session.

Summary

Configuring Stat with Kernel is a four field job plus one dropdown that trips people up:

  1. Copy one IP:PORT:USER:PASS line from the Connection panel in the Stat dashboard.
  2. Create a Kernel custom proxy from it, with protocol set to http, not the https default.
  3. Run kernel.proxies.check before you trust it.
  4. Pass proxy_id to kernel.browsers.create and drive the session with Playwright exactly as you would otherwise.
  5. Verify from both ends: the exit IP inside the session, and the usage and top domains panels on the Stat side.

One IP per concurrent agent, created once at startup and reused, is the shape that holds up over long logged-in runs. If you are still choosing a cloud browser, our cloud browser benchmark compares Kernel against Browserbase, Hyperbrowser, and Steel on session create and connect latency, and we have a matching walkthrough for proxies in Browserbase.

Need the IPs? Stat ISP plans start at $2.50 per proxy per month with unlimited bandwidth, US Tier 1 ISP addresses, and an API for adding capacity or replacing a burned IP mid-run.