Proxy account and password
ipx_demo8f2k / YOUR_PASSWORD
These are proxy credentials, not your sign-in email and password. Resetting the password in the console invalidates the old one immediately.
Hands-on tutorial
The goal is simple: send every request from a different mobile exit IP, and see for yourself that it really changes. curl only, copy-paste ready, about five minutes.
Written for a first integration. No proxy background needed — follow the steps in order. Every step states the expected result; if yours differs, jump to the troubleshooting table.
This is where most first integrations stall — the address you connect to and the IP the target sees are two separate things.
| Term | What it is | What you do |
|---|---|---|
| Entry node (gateway) | The gateway server your client connects to. Its address is stable. | Put it after curl -x and leave it alone. |
| Exit node | The phone that actually reaches the target site. It decides the IP and the region the target sees. | Select it with -region-<region> inside the proxy username; randomise across regions for random exits. |
In one line: the gateway address never changes. What changes is the username and how many connections you open.
The gateway picks an exit device at the moment a connection is established, so three things matter:
The username carries no -session- and no -sessTime-. With them you get a sticky session, which deliberately pins you to one exit IP.
Every request opens a new connection. On a reused keep-alive connection the request still travels the original tunnel, so the exit cannot change — this is the number one reason people report “my IP never rotates”.
To randomise across regions, pick one from your available-region list yourself and build it into the username before each request.
Rotating means “scheduled again”, not “guaranteed different”. When a region has few online devices, drawing the same one twice in a row is expected.
All three live on the Proxy access page in the console — keep it open and copy from it.
ipx_demo8f2k / YOUR_PASSWORD
These are proxy credentials, not your sign-in email and password. Resetting the password in the console invalidates the old one immediately.
HTTP proxy.gaofengxt.cn:20001 · SOCKS5 proxy.gaofengxt.cn:20002
HTTP and SOCKS5 listen on different ports; do not paste the SOCKS5 port into an HTTP example. This tutorial uses the HTTP port.
hangzhou / ningbo
A region slug is a city in the device pool. Requesting a region with no online device fails outright, so always take the list from the console.
Forget randomness for a moment and run the smallest working command. Replace the password with yours and paste it into a terminal:
curl -x proxy.gaofengxt.cn:20001 \
-U "ipx_demo8f2k-zone-mob-region-hangzhou:YOUR_PASSWORD" \
https://ipinfo.io/ipipx_demo8f2kYour proxy account, copied from the console.-zone-mob-region-A fixed infix — do not change or drop a single character.hangzhouThe exit region code; change this part to change cities.Expected result: one IP printed, for example 117.136.38.201. That is the address the target site sees right now. No output or an error? Skip to the troubleshooting table.
Run the same command five times in a row and compare:
for i in 1 2 3 4 5; do
curl -s --http1.1 \
-H 'Connection: close' -H 'Proxy-Connection: close' \
-x proxy.gaofengxt.cn:20001 \
-U "ipx_demo8f2k-zone-mob-region-hangzhou:YOUR_PASSWORD" \
https://ipinfo.io/ip
echo
doneWhy --http1.1 and the two Connection: close headers: curl reuses connections and negotiates HTTP/2 when it can, and requests on one connection share one exit tunnel, so the IP never moves. Disabling reuse forces a fresh scheduling decision per request. The same applies in code — do not funnel everything through one long-lived connection.
If all five match: check the username for -session-, then check that both headers really made it into the request. If both are fine, that region most likely has a single online device right now.
Put the regions in an array and draw one before each request:
REGIONS=(hangzhou ningbo)
REGION=${REGIONS[$((RANDOM % ${#REGIONS[@]}))]}
curl -s --http1.1 -H 'Connection: close' \
-x proxy.gaofengxt.cn:20001 \
-U "ipx_demo8f2k-zone-mob-region-$REGION:YOUR_PASSWORD" \
https://ipinfo.io/ipKeep the list aligned with the regions that have online devices in the console. Hard-coding an empty region simply fails that request.
The steps above, combined into a repeatable self test: random region, forced new connection, one exit IP per line, and a count of how many distinct exits you hit.
vi test_proxy.shCreate the file and paste the whole script below into it.
chmod +x test_proxy.shMake it executable.
export PROXY_PASSWORD='your-proxy-password'The password travels by environment variable only — never in the file, never in Git.
PROXY_USER_PREFIX=your-account-zone-mob-region COUNT=20 ./test_proxy.shSwap in your own prefix and run. Running it bare also works and uses the defaults below.
#!/usr/bin/env bash
# Random-exit self test: pick a random exit region per connection, print the real exit IP, then summarise.
set -u
# 1. Gateway address (HTTP port). The console is the source of truth.
PROXY_ADDRESS=${PROXY_ADDRESS:-proxy.gaofengxt.cn:20001}
# 2. Username prefix = your proxy account + the fixed -zone-mob-region
PROXY_USER_PREFIX=${PROXY_USER_PREFIX:-ipx_demo8f2k-zone-mob-region}
# 3. Exit regions to randomise over, comma separated
REGIONS=${REGIONS:-hangzhou,ningbo}
# 4. Number of connections
COUNT=${COUNT:-10}
# 5. Per-connect and overall timeout in seconds
CONNECT_TIMEOUT=${CONNECT_TIMEOUT:-10}
MAX_TIME=${MAX_TIME:-20}
# 6. Probe URL. It must return a plain-text IP.
TEST_URL=${TEST_URL:-https://ipinfo.io/ip}
# Read the password from the environment only. Never commit it.
if [ -z "${PROXY_PASSWORD:-}" ]; then
printf 'Error: set the PROXY_PASSWORD environment variable first.\n' >&2
exit 2
fi
case "$COUNT" in
''|*[!0-9]*|0)
printf 'Error: COUNT must be an integer greater than 0.\n' >&2
exit 2
;;
esac
# Split the comma-separated regions into an array
old_ifs=$IFS
IFS=',' read -r -a region_list <<< "$REGIONS"
IFS=$old_ifs
region_count=${#region_list[@]}
if [ "$region_count" -eq 0 ]; then
printf 'Error: REGIONS needs at least one region.\n' >&2
exit 2
fi
# Temp file holds every region + exit IP pair; removed on exit
results_file=$(mktemp "${TMPDIR:-/tmp}/proxy-exit-ip.XXXXXX") || exit 1
trap 'rm -f "$results_file"' EXIT
successful=0
failures=0
printf 'gateway: %s\n' "$PROXY_ADDRESS"
printf 'exit regions: %s\n' "$REGIONS"
printf 'connections: %s\n\n' "$COUNT"
for ((attempt = 1; attempt <= COUNT; attempt++)); do
# Pick a random exit region. No -session- in the username means rotating mode.
region=${region_list[$((RANDOM % region_count))]}
proxy_username="${PROXY_USER_PREFIX}-${region}"
# --http1.1 + Connection: close force a fresh connection; a reused one keeps the same exit
response=$(curl \
--silent --show-error --fail --http1.1 \
--connect-timeout "$CONNECT_TIMEOUT" \
--max-time "$MAX_TIME" \
-H 'Connection: close' \
-H 'Proxy-Connection: close' \
-x "$PROXY_ADDRESS" \
-U "$proxy_username:$PROXY_PASSWORD" \
"$TEST_URL" 2>&1)
curl_status=$?
if [ "$curl_status" -ne 0 ]; then
failures=$((failures + 1))
printf '[%03d/%03d] region=%-10s failed curl=%d: %s\n' \
"$attempt" "$COUNT" "$region" "$curl_status" "$response"
continue
fi
# Plain-text IP: trim whitespace, then check only digits and dots remain
exit_ip=$(printf '%s' "$response" | tr -d '[:space:]')
case "$exit_ip" in
''|*[!0-9.]*)
failures=$((failures + 1))
printf '[%03d/%03d] region=%-10s failed: the probe URL did not return a plain-text IP\n' \
"$attempt" "$COUNT" "$region"
continue
;;
esac
successful=$((successful + 1))
printf '%s\t%s\n' "$region" "$exit_ip" >> "$results_file"
printf '[%03d/%03d] region=%-10s exit_ip=%s\n' \
"$attempt" "$COUNT" "$region" "$exit_ip"
done
# More unique region/exit-IP pairs means more distinct devices were used
if [ "$successful" -gt 0 ]; then
unique_pairs=$(sort -u "$results_file" | wc -l | tr -d ' ')
else
unique_pairs=0
fi
printf '\nsummary: ok=%d failed=%d unique region/exit-IP pairs=%d\n' "$successful" "$failures" "$unique_pairs"
if [ "$successful" -gt 0 ]; then
sort "$results_file" | uniq -c | awk '{
printf " region=%s exit_ip=%s hits=%d\n", $2, $3, $1
}'
fi
# Exit 1 when anything failed so CI and monitors can react
if [ "$failures" -gt 0 ]; then
exit 1
fi
| Variable | Default | Description |
|---|---|---|
PROXY_PASSWORD | — | Proxy password. Required; the script exits without it. |
PROXY_ADDRESS | proxy.gaofengxt.cn:20001 | Gateway address (HTTP port). |
PROXY_USER_PREFIX | ipx_demo8f2k-zone-mob-region | Username prefix: your proxy account plus the fixed infix. The script appends -<region>. |
REGIONS | hangzhou,ningbo | Exit regions to randomise over, comma separated. |
COUNT | 10 | How many connections to open in total. |
CONNECT_TIMEOUT | 10 | Per-connection timeout in seconds. Mobile exits handshake slower than datacentres. |
MAX_TIME | 20 | Overall per-request timeout in seconds, including the target's response time. |
TEST_URL | https://ipinfo.io/ip | Probe URL. It must return a plain-text IP; your own endpoint works too, but then no IP can be parsed. |
If the default probe is unreachable from a mobile exit, use one of these instead: https://api.ipify.org · http://ip.3322.net
gateway: proxy.gaofengxt.cn:20001
exit regions: hangzhou,ningbo
connections: 5
[001/005] region=hangzhou exit_ip=117.136.38.201
[002/005] region=ningbo exit_ip=223.104.211.86
[003/005] region=ningbo exit_ip=223.104.211.86
[004/005] region=hangzhou exit_ip=39.144.72.14
[005/005] region=hangzhou exit_ip=117.136.38.201
summary: ok=5 failed=0 unique region/exit-IP pairs=3
region=hangzhou exit_ip=117.136.38.201 hits=2
region=hangzhou exit_ip=39.144.72.14 hits=1
region=ningbo exit_ip=223.104.211.86 hits=20Everything succeeded.1At least one attempt failed; see the per-line output.2Bad arguments or no PROXY_PASSWORD — no request was sent.The same two rules as with curl: no session in the username, and a fresh connection per request.
import random
import requests
from urllib.parse import quote
GATEWAY = "proxy.gaofengxt.cn:20001" # gateway HTTP port
ACCOUNT = "ipx_demo8f2k"
PASSWORD = quote("YOUR_PASSWORD", safe="") # escape @ : / in the password
REGIONS = ["hangzhou", "ningbo"]
def fetch(url: str) -> str:
region = random.choice(REGIONS) # random exit region
username = f"{ACCOUNT}-zone-mob-region-{region}" # no session = rotating mode
proxy = f"http://{username}:{PASSWORD}@{GATEWAY}"
# Connection: close forces a fresh connection so the exit changes
resp = requests.get(
url,
proxies={"http": proxy, "https": proxy},
headers={"Connection": "close"},
timeout=20,
)
resp.raise_for_status()
return resp.text.strip()
for _ in range(5):
print(fetch("https://ipinfo.io/ip"))
// Node 18+; install first: npm i undici
import { ProxyAgent } from "undici";
const GATEWAY = "proxy.gaofengxt.cn:20001";
const ACCOUNT = "ipx_demo8f2k";
const PASSWORD = encodeURIComponent("YOUR_PASSWORD");
const REGIONS = ["hangzhou", "ningbo"];
async function fetchViaRandomExit(url) {
// Random exit region; a username without session means rotating mode
const region = REGIONS[Math.floor(Math.random() * REGIONS.length)];
const username = `${ACCOUNT}-zone-mob-region-${region}`;
// A fresh agent per request; a pooled connection keeps the same exit
const agent = new ProxyAgent(`http://${username}:${PASSWORD}@${GATEWAY}`);
try {
const res = await fetch(url, { dispatcher: agent });
return (await res.text()).trim();
} finally {
await agent.close();
}
}
for (let i = 0; i < 5; i++) {
console.log(await fetchViaRandomExit("https://ipinfo.io/ip"));
}
Match the exact wording your terminal prints on the left.
| What you see | Cause | What to do |
|---|---|---|
curl: (5) Could not resolve proxy | The gateway hostname did not resolve. | Check local DNS and connectivity, and copy the address from the console rather than typing it. |
curl: (7) Failed to connect | The name resolved but the port refused the connection. | Confirm the port (HTTP and SOCKS5 differ), then check local firewalls or corporate egress rules. |
curl: (22) … 407 | Proxy authentication failed. | The username must include the whole -zone-mob-region-<region> segment; check for stray spaces and update the password if it was reset. |
curl: (28) Operation timed out | Connected, but no response in time — usually mobile jitter or a slow target. | Raise CONNECT_TIMEOUT / MAX_TIME and add retries in your code. |
503 · NO_ELIGIBLE_DEVICE | That region currently has no online device. | Use another region, or check the console for regions that still have devices. |
503 · TUNNEL_UNAVAILABLE | Devices exist, but the tunnel could not be established (exit-side network problem). | Retry or switch region; if it persists, contact support with the timestamp and region. |
403 · TARGET_DENIED | The destination matches the platform's outbound blocklist. | These requests are not retried on another device. Use a different destination, or contact support if the use case is legitimate. |
It works, but the IP never changes | The username carries a session, or the connection is being reused. | Drop -session- and -sessTime-, add --http1.1 and Connection: close, and stop reusing one connection pool in code. |
Sticky sessions, the REST API, and error codes live in the main documentation; live regions and credentials live in the console.