Sticky Proxy IP Changes and Their Six Causes
A sticky session pins a device, not an IP address. Find which of six causes changed your exit IP, from a missing -sid- to carrier NAT, and test it.
By Proxies.sx Team. Reviewed .
Sticky routing keeps your session on one device. It cannot stop that device's network from giving it a new public address. Add -rot-sticky-sid-<name>, send the identical username on every request, and expect mobile carriers to change the exit address on their own schedule.
In this guide
What the gateway pins
A session on our gateway is a name you choose with -sid-, tied to one endpoint: a mobile modem or a residential peer device. Every connection that sends the same session id is routed to that endpoint while it stays available. The public IP address belongs to the endpoint's network, and the network can change it.
With -rot-sticky, the gateway keeps the session on its endpoint even through a short drop: a device that has been offline for up to 60 seconds keeps the pin. Check the six causes below in order. The first four are settings you control.
# Sticky: same endpoint for every connection that sends sid "cart7"
psx_ab12cd-mbl-us-rot-sticky-sid-cart7
# Not sticky: no sid, so each connection gets a throwaway session
psx_ab12cd-mbl-us-rot-stickyCause 1: the username has no -sid-
Without -sid-, the gateway creates a new temporary session for each connection and discards it after at most five minutes. -rot-sticky on its own therefore sticks to nothing across connections. The same applies to the auto modes: without a session id there is nothing to keep between intervals.
Many HTTP clients open a new connection for each request unless you reuse a session object, so a missing -sid- shows up as a new exit on almost every request.
Cause 2: the session id is not the same string
The gateway normalizes the username before it reads the session id. Two ids that look different to you can become the same session, and two that look the same can become different ones.
- The whole username is lowercased, so
-sid-UserAand-sid-useraare one session. - Characters other than
a-z,0-9and_are removed, and the id is cut at 64 characters. - A hyphen ends the value.
-sid-run-2becomes sessionrun, and the2is skipped as an unknown token. Every run then shares one session. Userun_2. - The session is scoped to the pool and country. The same id with
mbl-usand withpeer-usgives two separate sessions on two endpoints.
The gateway currently accepts -session- as another spelling of -sid-. Older versions skipped it, and some of our earlier documentation still says so. Write -sid-. The username guide lists every repair the parser makes.
Cause 3: the rotation mode moves the session
| Mode | What happens to a session with a -sid- |
|---|---|
auto5, auto10, auto20, auto60 | After 5, 10, 20 or 60 minutes, the next connection triggers a fresh selection, which can land on a different endpoint. auto10 is the default when you write no -rot- token. |
sticky | Stays on its endpoint, tolerating a drop of up to 60 seconds. |
hard | Pins exactly like sticky. It does not mean a new IP for every request. |
ondemand | Without a sid, every new connection gets a new pick. With a sid, the session stays on its endpoint while the endpoint is online. |
A session without a -rot- token rotates every 10 minutes. If you meant to hold the endpoint, write -rot-sticky explicitly. An open connection is not interrupted by rotation. The change applies to the next connection the session makes.
Cause 4: the session expired
A session with a -sid- lives for one hour after its last use by default, and each use renews that hour. A worker that pauses for longer than the TTL comes back to a new session on a new endpoint. Set the TTL in seconds with -ttl-. The gateway accepts values from 60 to 2,592,000 (30 days) and clamps anything outside that range.
Expired sessions also stop counting toward the account's session limit. A long TTL on thousands of unique ids keeps them all counted, and the account can hit E_SESSION_LIMIT (429 codes).
# Keep the session for 6 hours of inactivity instead of 1
psx_ab12cd-peer-us-rot-sticky-sid-acct42-ttl-21600Cause 5: the device left or moved
Devices go offline: a phone loses signal, a home connection drops, a modem restarts. When a sticky session's endpoint has been offline for more than 60 seconds, the gateway drops the pin and applies the session's failover policy. The default, samecountry, picks another endpoint in the same country. The session id stays the same, and the exit address changes because the device changed.
The gateway also drops a pin when the endpoint now geolocates to a different country from the one in your username. A country in the username is treated as a requirement.
| Failover token | Behavior when the pinned endpoint is gone |
|---|---|
-failover-samecountry | Default. Move to another endpoint in the same country. |
-failover-samecarrier | Move only to an endpoint on the same carrier. |
-failover-any | Move to any endpoint that matches the pool, even in another country. |
-failover-strict | Never move. Requests fail with E_NO_STOCK_COUNTRY (502) until the original endpoint returns. |
Use strict when a changed device is worse for you than a failed request, for example in a logged-in workflow where a new address triggers a security check.
Cause 6: the carrier changed the address
Mobile carriers put many subscribers behind carrier-grade NAT (CGN). The phone or modem holds a private address, often from the 100.64.0.0/10 range reserved for this purpose (RFC 6598), and the carrier maps its traffic to public addresses from a shared pool.
RFC 6888 requires CGNs to use "paired" pooling by default, which keeps one subscriber's simultaneous mappings on one external address (RFC 6888, REQ-2). That rule covers mappings that exist at the same time. It says nothing about the address a later mapping gets once the earlier ones have expired, and that address can differ. The carrier decides when, and the gateway sees the same device throughout.
This is why a perfectly pinned mobile session can show several exit addresses in an hour. The mobile IP pool math article explains why a short sample cannot tell you how large a carrier's address pool is. If a workflow needs one address for its whole duration, test a residential peer in your target country with the script below and measure how long the address holds for your use before you rely on it.
Measure what your session does
This script sends the same sticky username every 20 seconds through one Requests session and prints a line only when the exit address changes or a request fails. A change with no error between samples fits carrier NAT or a failover, while a run of errors followed by a change points to the device leaving. From the client side you cannot tell carrier NAT and failover apart with certainty.
For a browser-based check, the rotation checker samples exit addresses for you, and testing mobile proxy IP rotation covers a longer method. The output below uses documentation addresses from RFC 5737 in place of exit IPs.
import os
import time
from urllib.parse import quote
import requests
user = "psx_ab12cd-mbl-us-rot-sticky-sid-probe1"
password = quote(os.environ["PROXY_PASSWORD"], safe="")
proxy = f"http://{user}:{password}@gw.proxies.sx:7000"
session = requests.Session()
session.proxies = {"http": proxy, "https": proxy}
last = None
for _ in range(90): # about 30 minutes
stamp = time.strftime("%H:%M:%S")
try:
ip = session.get("https://api.ipify.org", timeout=20).text.strip()
except requests.RequestException as error:
print(stamp, "error", type(error).__name__)
else:
if ip != last:
print(stamp, "exit", ip)
last = ip
time.sleep(20)
# Example output (documentation addresses):
# 14:02:10 exit 203.0.113.24
# 14:19:30 exit 203.0.113.91Common questions
Does -rot-hard give me a new IP on every request?
No. hard pins the session exactly like sticky. For a fresh pick, open a new connection with -rot-ondemand and no sid, or change the sid.
How many sticky sessions can one account run?
The default limit configured on 19 October 2026 is 1,000 active sessions per account, and an administrator can set a different limit for an account. Past the limit, new sessions get E_SESSION_LIMIT (429). Expired sessions stop counting.
Can I choose which IP address I get?
The Pool Gateway selects endpoints by pool, country and filters such as carrier and city. It does not take a requested address.
Sources and test scope
Standards and vendor documentation checked on 19 October 2026. Gateway responses on these pages were observed with test requests or read from the gateway build running that day, and the client examples were run against local test servers. They do not establish current stock in a country or how a website will respond.
Connect your application to Proxies.sx
Use the username builder for gateway routing fields and the format converter for existing connection lists. Review Pool Gateway documentation, then check current mobile stock before buying traffic.
For agent-driven workflows, the agent service index lists the supported APIs. A configured HTTP client still needs to validate its task's response.
Proxy error and troubleshooting guides
Start from the symptom table, or open the guide for the error you saw.