How it works · for dummies

Websites judge you by your IP. This is the switchboard that picks which IP your agent wears.

Every device on the internet has an address. Search, shops, ads, and news sites use that address to decide what you see — currency, language, rankings, even whether the page loads at all. An AI agent in a datacenter has one address: that datacenter. Without a localized exit, every fetch looks like it came from one building.

You ask for a country or city. IP Router picks an exit there, sends the request out through that IP, and hands the page back. Same brain for a JSON agent and a real browser.

The idea

Four facts, then you can use the rest.

The website never sees your laptop

It sees the exit IP. Change the exit, change the page — prices, SERP, store locator, paywall, all of it.

Country is not language

cc-JP puts you on a Japanese IP. lang-ja tells the site you read Japanese. You usually want both.

Sticky means “same person”

Logins, carts, and cookies die if the IP flips mid-flow. A sessid pins you to one exit until it expires.

Two doors, one kernel

Agents POST JSON to /api/v1/fetch. Browsers and curl talk CONNECT on :7777. Both call selectRoute.

Words

The dozen terms the console uses.

IP / exit
The address the website sees. Not your laptop, not the agent host — the last hop that left IP Router.
cc (country)
ISO country code. GB is the United Kingdom, DE is Germany, JP is Japan. This picks the market.
city
Finer than country. London vs Manchester, New York vs Austin. Spaces become underscores in usernames: city-new_york.
lang
Accept-Language header. The site’s “what language do you read?” question. Independent of the IP.
sessid (sticky)
A name you reuse so every hop in a job uses the same exit. Default TTL is 10 minutes; sesstime overrides it.
type
What kind of network the exit is: residential, datacenter, mobile, or ISP. Sites treat these differently.
pool
A list of nodes you added, each tagged with a country and maybe a city. The router matches targeting to a node.
backconnect
One vendor gateway. IP Router appends -cc-US-city-austin-sessid-job1 onto that vendor’s username.
direct
This machine. Fine for learning. The website still sees your host IP, so geo pages will not change.
IP farm
Android phones you rack in a city. Agents leave through that last mile, billed per live connection — not per GB.
Fetch API
POST /api/v1/fetch with JSON. For agents and LLMs that do not speak HTTP CONNECT.
Gateway :7777
An HTTP proxy. curl -x, Playwright, browsers. Targeting lives in the username, Oxylabs-style.
Two doors

Same targeting. Different clients.

Pick the door that matches how your client talks. Targeting is the same either way.

Fetch API — the agent door

Use this when your client posts JSON: an LLM tool, a script, a n8n node, the playground.

POST /api/v1/fetch with a Bearer key. Put country, city, language, session in the body. The response includes the page, the exit geo, and route.reason so you can see why that hop was chosen.

It fetches a URL and returns the body. It does not click, fill forms, or keep a real browser cookie jar. For a checkout in a real browser, use the gateway.

HTTP gateway — the browser door

Use this when the client already speaks HTTP proxy: curl -x, Playwright, Chrome, a scraper that expects CONNECT.

Point the proxy at host:7777. Username is iprouter-{keyId}-cc-GB-city-london-sessid-job1. Password is the API key. Same targeting tokens as the fetch body, just in the username.

CONNECT cannot rewrite HTTPS headers. If you need Accept-Language on a TLS site, the browser (or fetch API) must send it. lang- in the username is a hint for routing and for HTTP, not a magic HTTPS inject.

If you areUse
JSON agent / LLM toolFetch API
Playground / try a URLFetch API
curl, Playwright, a real browserGateway :7777
Login then crawl the same sessionEither door, plus a sessid
Exits

Where the request actually leaves.

An exit is where the request leaves the internet as far as the website is concerned. You need at least one that is not “this machine” before geo pages will change.

Direct — this machine

Ships with the node. Requests succeed immediately so the playground works. route.reason will say “direct” or “direct fallback (no geo node)”. The website still sees your host IP.

Pool — IPs you added

Console → Proxy pool. Each node has a country, optional city, and a type. Ask for London; a London pool node wins. Ask for GB with no city; any GB node wins.

Backconnect — one vendor gateway

You add one gateway. IP Router injects targeting into the username (-cc-DE-city-berlin-sessid-s1). Use this when you buy bandwidth from a provider instead of listing every IP.

IP farm — phones in a city

Rack Android phones, tag the site with a country and city, set how many connections are live. Agents leave through that last mile. Billed per connection per month. A 14-day trial covers the first phone.

When you name a country, the router tries in this order: city pool match → country pool match → backconnect geo injection → direct fallback. No enabled proxies at all is a 422, not a silent miss.

First try

Five minutes. You do not need a paid exit yet.

Do this once so the rest of the guide is not abstract. Five minutes. You do not need a paid exit yet.

  1. 01

    Landing → Open console. Locally there is no signup. You land on Overview.

  2. 02

    Playground is pre-filled with the local echo. Pick a country (US is fine). Leave session as agent-demo. Send. You always get a 200 from echo — this proves the door, not the geo.

  3. 03
    Read three fields

    ok should be true. route.reason tells you which exit was chosen. geo.exit is the IP the outside world would see — empty or your machine on direct.

  4. 04

    Add a pool or backconnect node under Proxy pool, or an IP farm in a city you care about. Send again. reason should no longer say “direct fallback”.

  5. 05

    API keys for the Fetch API. Endpoints builds the gateway username. Agents has the LLM tool schema. Same targeting, three skins.

Use cases

How it works for each job.

Same knobs every time: country, city, language, sticky, type. The job only changes which ones you turn and which door you walk through. Pick a row.

city / country

See search the way someone in that city sees it

Google (and Bing, and maps) do not show one internet. They show the internet from where you are standing. Rankings, the local pack, ads, even which spelling they think you meant — all of that keys off the exit IP and the language header. If your agent fetches from a US datacenter, you are grading a US result page, even when the question is “what does this look like in Manchester.”

Without IP Router

You get the host country’s SERP. A London query from a Virginia VM is still a Virginia page with a London-shaped query string.

With it

cc-GB + city-london + lang-en_GB. The hop leaves through a UK exit, Accept-Language is British English, and the page is the one a London visitor would get.

How it works

  1. 01Name the market: country GB, city London, language en-GB. City matters here — Manchester and London are different local packs.
  2. 02Use the Fetch API if you want HTML/JSON back for the agent to read. Use the gateway if a headless browser is driving the SERP.
  3. 03Send a stable sessid if you will paginate or click through. A new session mid-scroll looks like a new visitor.
  4. 04Read route.reason. You want city pool match (or backconnect geo injection). Direct fallback means you are still on the host.
  5. 05Compare two runs: same query, US vs GB. The local pack and ads should move. If they do not, you are not on a geo exit yet.
Door

Fetch for snapshots the agent can parse. Gateway when Playwright is clicking through results.

cc-GBcity-londonlang-en_GB
Fetch API
{
  "url": "https://www.google.com/search?q=best+coffee+near+me",
  "geo": { "country": "GB", "city": "London", "language": "en-GB" },
  "session": "serp-london"
}
Gateway :7777
curl -x http://iprouter-key_dev-cc-GB-city-london-lang-en_GB-sessid-serp-london:ipr_live_dev_key@127.0.0.1:7777 https://www.google.com/search?q=best+coffee+near+me
You know it worked when

route.reason is a geo hit, geo.exit is not your host, and the local pack names London businesses — not the ones next to your server.

Common mistakes

  • Country only. GB without a city often lands you on a national page missing the local pack you cared about.
  • No lang. A UK IP with en-US still leans American spelling and US properties in the mix.
route.reason

The sentence that tells you if geo actually happened.

city pool match
You asked for a city and a pool node in that city was enabled. Best geo hit.
country pool match
No city node (or you did not ask for a city), but a pool node in that country was enabled.
backconnect geo injection
No pool node in that country. A backconnect gateway is on, so targeting was written into its username.
direct fallback (no geo node)
Nothing in that country. The request still left — through this machine. Geo pages will not change. Add a node or a farm.
sticky session
You reused a sessid and the old exit is still enabled. Same IP as last time. TTL refreshed.
backconnect rotate / pool rotate / direct
You did not name a country. The router picked any matching exit and, if you sent a session, hashed the pick so it stays put.
Mistakes

The ones that look like product bugs.

Country without language

A Japanese IP with an English Accept-Language often still serves English. Set lang (or language in the fetch body) as well as cc.

New sessid every request

If the session string changes, you are a new person. Logins drop. Reuse the same sessid for the whole job.

Trusting direct fallback

A 200 from echo on this machine is not proof of geo. Read route.reason. If it says direct fallback, the website still saw your host.

Datacenter vs residential

Some origins fingerprint ASN. If the page is a captcha wall or a “datacenter detected” blank, set type-residential or use an IP farm.

HTTPS + gateway + lang

The gateway cannot inject Accept-Language into an HTTPS CONNECT tunnel. Send the header from the client, or use the Fetch API.

Empty pool

If every node is disabled, you get 422 “No enabled proxies in the pool.” Enable the direct node or add one that is on.