Proxynator

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.

Proxynator team 5 min read Updated

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:PASS@proxy.proxynator.com: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:PASS@proxy.proxynator.com: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.

Without changing any code

curl, Python requests and httpx also read the standard proxy variables. Export them and an existing script goes through the phone as it is:

export HTTPS_PROXY="$PROXY_URL"
export HTTP_PROXY="$PROXY_URL"
python your_script.py

This is handy for a quick test, but it applies to every request the process makes, including calls to your own services. Set NO_PROXY for hosts that should go direct, or pass the proxy explicitly as in the examples below. Node’s built-in fetch ignores these variables by default, so use the agent shown in the Node.js section.

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())

Scrapy

Scrapy’s built-in proxy middleware reads the proxy from each request’s meta, including the login in the URL:

import os
import scrapy


class IpSpider(scrapy.Spider):
    name = "ip"

    def start_requests(self):
        yield scrapy.Request("https://api.ipify.org?format=json", meta={"proxy": os.environ["PROXY_URL"]})

    def parse(self, response):
        yield response.json()

Scrapy opens many requests in parallel, so set CONCURRENT_REQUESTS below your plan’s connection limit, and enable RETRY_ENABLED with a few extra RETRY_TIMES so pages requested during a rotation are fetched again instead of being lost. For long crawls, rotate between batches rather than on a timer, as described further down.

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);

Playwright and headless browsers

Browsers take the proxy when they launch, with the login passed separately rather than inside the URL. This Playwright example splits the same PROXY_URL into those parts:

import os
from urllib.parse import urlsplit
from playwright.sync_api import sync_playwright

u = urlsplit(os.environ["PROXY_URL"])
with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": f"http://{u.hostname}:{u.port}",
        "username": u.username,
        "password": u.password,
    })
    page = browser.new_page()
    page.goto("https://api.ipify.org")
    print(page.inner_text("body"))
    browser.close()

Use the HTTP form of the proxy in browsers: Chromium does not support SOCKS5 with a username and password. Puppeteer works the same way with --proxy-server=http://HOST:PORT and page.authenticate({ username, password }). One browser context per proxy login keeps cookies and IPs from mixing, which matters when you manage several accounts.

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: 50 on Basic and 300 on Pro. 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 Pro) 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: false when 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: 50 on Basic and 300 on Pro. 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. Try it for a day from $1.00.

Get started

#python#nodejs#curl#api#automation