Use a Mobile Proxy in Python, Node.js and curl
Working examples for curl, Python and Node.js: send requests through your mobile proxy, check the exit IP, rotate it from code, and retry cleanly while the phone reconnects.
This tutorial shows the same three tasks in each language: send a request through the proxy, confirm the exit IP, and rotate the IP from code. Every example reads the credentials from environment variables, so set these first:
export PROXY_URL="http://USER:[email protected]:PORT"
export PROXYNATOR_API_KEY="your-api-key"
export PHONE_ID="your-phone-id"
curl
curl is the quickest way to check that the proxy works.
# HTTP proxy
curl -x "$PROXY_URL" https://api.ipify.org
# SOCKS5, with DNS resolved by the proxy
curl -x "socks5h://USER:[email protected]:PORT" https://api.ipify.org
The output should be the phone’s carrier IP, not your own. If you get 407, the login is wrong; if the command hangs, check that the phone shows as online.
Python with requests
import os
import requests
proxy = os.environ["PROXY_URL"]
proxies = {"http": proxy, "https": proxy}
r = requests.get("https://api.ipify.org?format=json", proxies=proxies, timeout=30)
print(r.json()) # {"ip": "..."}
For SOCKS5, install the extra (pip install "requests[socks]") and use a socks5h:// URL in the same proxies dictionary.
Python with httpx
import os
import httpx
with httpx.Client(proxy=os.environ["PROXY_URL"], timeout=30) as client:
print(client.get("https://api.ipify.org?format=json").json())
Node.js
Node’s built-in fetch is powered by undici, which ships a proxy agent:
import { fetch, ProxyAgent } from "undici";
const dispatcher = new ProxyAgent(process.env.PROXY_URL);
const res = await fetch("https://api.ipify.org?format=json", { dispatcher });
console.log(await res.json());
With axios, pass an agent from the https-proxy-agent package; for SOCKS use socks-proxy-agent:
import axios from "axios";
import { HttpsProxyAgent } from "https-proxy-agent";
const agent = new HttpsProxyAgent(process.env.PROXY_URL);
const { data } = await axios.get("https://api.ipify.org?format=json", { httpsAgent: agent, proxy: false });
console.log(data);
Rotating the IP from code
There are two ways: the REST API (needs your API key) or the phone’s change-IP link (needs only the link).
| Method | Request | Best for |
|---|---|---|
| REST API | POST /api/v1/phones/PHONE_ID/rotate with a bearer key |
Your own software, several phones |
| Change-IP link | GET /change-ip?key=PHONE_KEY |
Tools that can only call a URL |
Rotate and wait in Python
import os
import time
import requests
API = "https://proxynator.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['PROXYNATOR_API_KEY']}"}
PHONE = os.environ["PHONE_ID"]
def rotate_and_wait(timeout=120):
old_ip = requests.get(f"{API}/phones/{PHONE}", headers=HEADERS, timeout=15).json().get("ip")
requests.post(f"{API}/phones/{PHONE}/rotate", headers=HEADERS, timeout=15).raise_for_status()
deadline = time.time() + timeout
while time.time() < deadline:
time.sleep(5)
phone = requests.get(f"{API}/phones/{PHONE}", headers=HEADERS, timeout=15).json()
if phone.get("online") and not phone.get("rotating") and phone.get("ip") != old_ip:
return phone["ip"]
raise TimeoutError("phone did not come back with a new IP")
print("new IP:", rotate_and_wait())
Retry while the phone reconnects
Requests sent during a rotation fail. A small retry with a growing delay keeps a script running through it:
import time
import requests
def get_with_retry(url, proxies, attempts=6):
delay = 5
for i in range(attempts):
try:
return requests.get(url, proxies=proxies, timeout=30)
except requests.RequestException:
if i == attempts - 1:
raise
time.sleep(delay)
delay = min(delay * 2, 40)
Running requests in parallel
A phone serves many connections at once, up to the plan’s limit: 25 on Lite, 100 on Pro and 300 on Max. Use a connection pool or a semaphore in your code to stay below it, and remember that a rotation drops every open connection, so pause your workers before rotating.
If several tools share one phone, give each its own login (more than one login is part of Max) so you can see and cap their traffic separately.
Troubleshooting
- 407 Proxy Authentication Required. Wrong login, or special characters in the password that need URL-encoding (for example
@becomes%40). - Timeouts. The phone may be offline or rotating. Check its status in the dashboard or through the API.
- The exit IP is your own. The library isn’t using the proxy. In axios, set
proxy: falsewhen you pass your own agent. - 429 Too Many Requests from the site. The target is rate-limiting this IP. Slow down, or rotate between batches; see rotating vs sticky sessions.
Summary
Using a mobile proxy in code is one setting in every major HTTP library. Add the rotation API and a retry loop, and you have a script that changes its IP between batches and keeps going while the phone reconnects.
Frequently asked questions
Where do I find my proxy username, password and port?
+
In the dashboard, open the phone. Its proxy login, port and ready-made connection strings are shown there, along with the change-IP link.
Should I put credentials in my code?
+
No. Read them from environment variables or a secrets file, as in the examples, so they don't end up in version control.
Why do requests fail right after I rotate?
+
The phone is reconnecting to the mobile network, which takes 20 to 60 seconds. Wait until the API reports the phone online again, or retry with a back-off.
How many requests can I run in parallel?
+
Up to the plan's connection limit: 25 on Lite, 100 on Pro and 300 on Max. Keep some headroom, because one HTTP request can use more than one connection.
Run your own mobile proxy
Install the Proxynator app on a spare Android phone with a SIM card and get an HTTP and SOCKS5 proxy on a real carrier IP. The first phone gets a 2-day Max trial.