Quickstart

A working proxy request in about two minutes. Your account includes 1 GiB of free traffic; it does not expire and there is no card on file.

Your credentials#

Hostgate.busyip.com
HTTPport 18080 (HTTP CONNECT)
SOCKS5port 11080
Usernamebi_k4m2xq7r
Password•••••••••••• shown once, at signup — rotate if lost

The examples on this page use bi_k4m2xq7r as a stand-in. Your own username is in your dashboard, and every sample below works with it unchanged.

First request#

curl · HTTP CONNECT
curl -x http://bi_k4m2xq7r:YOUR_SECRET@gate.busyip.com:18080 https://api.ipify.org

That prints an IP address belonging to a real mobile or home connection, not ours. Run it twice and you may get a different one — see Sessions.

curl · SOCKS5
curl -x socks5h://bi_k4m2xq7r:YOUR_SECRET@gate.busyip.com:11080 https://api.ipify.org

Use socks5h, not socks5, so DNS is resolved at the exit rather than on your machine. Without the h your own resolver decides, and the exit's location stops matching what the site sees.

Targeting: the username is the control surface#

You select what you want by appending markers to your username. The password never changes. That is why every tool taking a proxy URL supports all of it with no plugin.

Grammar
bi_k4m2xq7r[-session-{id}][-country-{cc}][-type-mobile|residential|any][-mode-sticky|rotate]
You wantUsername
Anything availablebi_k4m2xq7r
A mobile (cellular) exitbi_k4m2xq7r-type-mobile
A home Wi-Fi exitbi_k4m2xq7r-type-residential
Moldovabi_k4m2xq7r-country-md
Moldova, mobilebi_k4m2xq7r-country-md-type-mobile
A stable IP across requestsbi_k4m2xq7r-session-abc123
A new IP on every requestbi_k4m2xq7r-mode-rotate

-net- is accepted as a synonym for -type-, and cellular, cell and wifi are accepted spellings. An unknown type matches nothing rather than everything — if you typo it you get no_capacity, never a silent fallback to the wrong pool.

Sessions — and the one behaviour to understand#

A -session-{id} pins you to a single exit device. A session id with no -mode- is sticky by default. Sessions idle for 24 hours are released.

Two things that sentence does not promise, because we measured both and neither is true on a fleet this size. The same session does not guarantee the same IP. It pins the phone; the phone's carrier can hand it a new address underneath you, and we have watched a session move between two addresses in the same /24 seconds apart. If your work is bound to an IP rather than to a device, treat a change as possible and check it. And a different session id does not guarantee a different IP. Stickiness is a promise about staying, never about differing — with a small pool two sessions frequently land on the same phone. If you need two addresses at once, ask us what is online rather than assuming two ids will do it.

If the phone behind your session goes offline, we tell you. We do not silently move you.

Response body
{"error":"sticky_device_offline","suggestedSession":"abc124"}

Read the reason from the headers, not the body. Every refusal carries X-Proxy-Error and X-Proxy-Message, and a transient one also carries X-Proxy-Retryable: true. Those survive the CONNECT tunnel. The JSON body does not — essentially every HTTP client discards the body of a failed CONNECT, including curl, requests, Go and OkHttp, so a client that parses the body sees nothing at all and reports an empty response.

Most providers fail this open — you keep making requests and your IP has quietly changed underneath you, which for anything session-bound means you find out from the target site, not from the proxy. We would rather hand you an error you can branch on. Retry with the suggested session id to get a fresh pin.

Errors#

Every rejection is a 403 with a {"error","message"} JSON body on the HTTP port, and SOCKS reply 0x02 (not allowed by ruleset) on 11080. The messages are safe to read and act on — they name the rule you hit and never describe the exit's own network.

If you are new, concurrency_limit is the one you will meet first. A trial credential allows 2 connections at once and most scraping libraries open ten or more by default, so a first run can produce a burst of denials that looks like something is broken. Nothing is — set your connection pool to 2. A paid credential allows 8.

no_capacity is the one you will meet after that. Our fleet is small and every exit is a real person's phone that they can close at any moment. Build a retry with backoff and treat it as "try again in a moment", not as a failure.

CodeMeansDo
invalid_credentials Wrong username or password. Check the secret; rotate it from the dashboard if it is lost.
quota_exhausted Your balance is spent. Top up. Requests already in flight are given a short grace.
no_capacity No exit matches your filters right now. Retry with backoff, or widen — drop -country- or -type-.
sticky_device_offline The exit you were pinned to dropped. Retry with the suggestedSession we hand back.
session_required -mode-sticky without a -session-. Add a session id.
device_unavailable The exit accepted the request and then could not open a connection. A transient failure, and the response says so: X-Proxy-Retryable: true. Retry immediately — a fresh request is usually handed a different exit. This is the one error worth automating a retry on.
scope_not_permitted Your credential is limited to a country or type you did not ask for. Use the credential's own scope.
ip_not_allowed Your source IP is not on the credential’s allowlist. Update the allowlist in the dashboard.
concurrency_limit More connections at once than your credential allows. Trial allows 2 at once; paid allows 8. Set your client’s connection pool to match — most scrapers default to 10 or 16.
port_blocked The target port is not permitted. We allow 80 and 443 only. The message names the permitted ports.
host_blocked The target is a private or reserved address. Private, loopback, link-local and CGNAT ranges are unreachable by design.
bad_destination The address could not be parsed. Check the host you asked for.
resolve_failed DNS lookup for the target failed. We fail closed on a resolution failure rather than guessing.
credential_expired Unused for 180 days. Rotate from the dashboard.
disabled The credential is suspended. Contact support@busyip.com.

Code#

Python · requests
import requests

PROXY = "http://bi_k4m2xq7r:YOUR_SECRET@gate.busyip.com:18080"
r = requests.get("https://api.ipify.org",
                 proxies={"http": PROXY, "https": PROXY}, timeout=30)
print(r.text)

Pin a session by putting the marker in the username:

Python · a pinned session
PROXY = "http://bi_k4m2xq7r-session-abc123-country-md:YOUR_SECRET@gate.busyip.com:18080"
Node · undici
import { ProxyAgent, request } from "undici";

const agent = new ProxyAgent("http://bi_k4m2xq7r:YOUR_SECRET@gate.busyip.com:18080");
const res = await request("https://api.ipify.org", { dispatcher: agent });
console.log(await res.body.text());
Playwright
const browser = await chromium.launch({
  proxy: {
    server:   "http://gate.busyip.com:18080",
    username: "bi_k4m2xq7r-session-abc123",
    password: "YOUR_SECRET",
  },
});

Playwright takes the username and password as separate fields, so the markers go in the username — not in the server URL.

Anything that takes a proxy URL — Scrapy, curl, yt-dlp, a browser extension — takes the same string. There is no SDK to install and there never will be; it is a standard proxy.

AI assistants (MCP)#

busyip exposes an MCP server at https://busyip.com/mcp. Point an AI client at that URL and it can answer questions about the service, and — once you connect an account — check your balance, read your usage, and rotate your proxy password for you.

Six tools need no account at all

busyip_overview, busyip_pricing, busyip_capacity, busyip_metering, busyip_targeting and busyip_legal answer with no token. That is deliberate: an assistant deciding whether to recommend us should be able to read the live capacity and the honest limits before anybody signs up. busyip_capacity in particular reads the fleet live, so it will tell you a country is unavailable rather than let you promise it.

Six more act on your account

Balance, usage, orders, credential, account state, and rotating the proxy secret. These need a token and are scoped to exactly one account — no tool takes an account identifier, so a token can only ever reach the account it was issued for. None of them can read your current proxy password, because it is not stored; the only way to obtain a working one is to rotate.

Sign-in

busyip is a standard remote MCP server — Streamable HTTP with OAuth 2.1 Dynamic Client Registration and PKCE. Point a client at the URL and it discovers and registers itself; there is no client ID or secret to paste. The first connection opens a browser, you sign in and press Approve, and the client keeps its own token from then on. Access is scoped to that one account.

Claude app (Desktop / web)

  1. Open Settings → Connectors
  2. Add custom connector
  3. Name it busyip and paste https://busyip.com/mcp
  4. Press Connect, then sign in and press Approve

Claude Code (CLI)

One command:

claude mcp add --transport http busyip https://busyip.com/mcp

OpenAI Codex CLI

Add a streamable-HTTP server to ~/.codex/config.toml:

[mcp_servers.busyip]
url = "https://busyip.com/mcp"

Or the equivalent command:

codex mcp add busyip --url https://busyip.com/mcp

Grok, or any other MCP client

Settings → Connectors / Integrations → Add MCP server → remote / HTTP, paste https://busyip.com/mcp, authorise.

Clients that only take a header

Create a token at /app/mcp and send it as Authorization: Bearer bimcp_…. Tokens are revocable from that page and revoking takes effect on the next request, however the token was issued.

Discovery documents, if you want to look before connecting: /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource.

What we count#

  • 1 GB means 1 GiB = 1,073,741,824 bytes. We say GiB where it matters and never round in our favour.
  • We bill wire bytes in both directions, including TLS handshakes and protocol overhead. Your application-level counter reads lower than ours, and the size of that gap is driven by how much you transfer per connection rather than by anything we choose. Measured on this network: +5.6% on a 120 KB fetch, and +46% on a 7 KB fetch that paid for its own TLS handshake. Reuse connections and the gap collapses toward the first number. All of it is real traffic a real person's phone carried, and they are paid for it. If your numbers do not fit that shape, tell us.
  • Nothing is rounded per request or per connection, and there is no minimum billable unit.
  • Enforcement is checked on a short interval, so a request in flight when your balance hits zero is allowed a bounded grace of up to 64 MiB rather than being cut mid-response. Those bytes are carried against your next top-up — they show as a negative balance until then, and at 64 MiB that is a few cents at most.
  • Usage in the dashboard lags live traffic by up to a minute.

The pricing page states the same thing in one sentence.

Limits on the trial#

 TrialPaid
Traffic1 GiBWhatever you buy
Concurrent connections28
Countries / typesAll availableAs sold
Bytes expire?NeverNever

Buying does not give you new credentials. The username and password above are yours for the life of the account — a purchase adds bytes to the same credential and lifts the concurrency limit. The code you just got working keeps working; you do not re-paste anything.

Honestly, what this is not#

We are a small fleet of real phones, not a 40-million-IP pool. Concretely:

  • Availability is not yet guaranteed. There are hours when few or no exits are online.
  • Do not build a job that must finish on a deadline against us today.
  • Country coverage is thin. If -country-xx returns no_capacity consistently, that country has no exit online — and we would rather you knew that than have us route you elsewhere and call it Moldova.

Every exit is a person who installed our app, agreed to share their connection, and is paid per gigabyte. On cellular they are a mobile IP; on Wi-Fi, a residential one. That is the whole product, and it is why the pool is small and why we can tell you exactly where your traffic came from.

If it will not connect at all#

  • Timeouts on every request, no error body. Something between you and us is blocking port 18080 — corporate firewalls commonly allow only 80/443 outbound. Try the SOCKS5 port, or test from a different network.
  • DNS looks wrong, or sites resolve to the wrong region. Use socks5h://, not socks5://.
  • It worked, then stopped. Check your balance first — an exhausted balance returns quota_exhausted, not a timeout.

Still stuck? Email support@busyip.com. One person reads it and they can see your account.