What Is IP Rotation and How Does It Work?

Published:

20 minute read

Acar Diveroli
Written by: Acar Diveroli
Hundreds of exit paths fanning out from a single gateway core, with labels showing three different exit IP addresses

You bought a rotating proxy, wired your script to it and sent three requests in a row to an IP echo service. All three came back with the same address. Or the opposite happened: a script that logs in to your own dashboard landed on the login screen again on page two, because the exit IP changed in the middle of the session. In neither case is the proxy broken. The setup was built without knowing which event triggers the rotation.

In this post we define IP rotation briefly and then move on to the real subject, how the process works: the path a request takes behind a gateway, the three rotation modes (per request, timed, sticky session), the terms that get mixed up, connection reuse as the most common reason the IP does not change the way you expect, and the things rotation breaks. At the end there is a short, tested Python example that verifies rotation, and a decision guide.

What is IP rotation?

IP rotation (also called proxy rotation) means the exit IP used for outgoing network requests does not stay on one address but changes among the addresses of an IP pool. The service that does this for you is called a rotating proxy; the product definition, the pool and the targeting options are covered on that page. Here we look at the process, not the product: when the IP changes, when it does not, and who decides.

The idea is not really foreign. The dynamic IP on your home connection is a kind of rotation too: your provider changes your address from time to time, but you cannot decide when it changes or which address you get. We covered that side in Static IP vs Dynamic IP and How to Change Your IP Address. What sets proxy rotation apart is that control is yours: you choose how often the address changes, which country it comes from and which requests leave from the same address.

What is rotation good for, and what is it not?

Rotation has three legitimate purposes:

  • Spreading load. A job that collects the public pages of hundreds of sites and sends all its traffic from one address puts more requests on that address than any real visitor could produce. Rotation keeps the load per address at a reasonable level.
  • Seeing content by location. Prices, stock and search results change with the visitor's country. Pinning the pool to a country or a city and rotating inside that location gives you the real view of that market.
  • Keeping sessions apart. Independent jobs (different client accounts, different test scenarios) each leave from their own address; one does not carry the trace of another.

Where it does not help is just as clear. If the site asked you to slow down with a 429, closed a path in robots.txt or prohibits automated access in its terms, changing the IP and carrying on at the same speed does not solve the problem; it ignores a preference the site owner stated openly. The full framework is in How to Scrape Websites Without Getting Blocked, and the right response to a 429 is in 429 Too Many Requests and Rate Limiting Explained.

How does rotation work through a gateway (backconnect)?

In old-style rotation you hold a proxy list and your code picks the next address. In the gateway model you do not hold the list. You connect to a single host:port address and the provider manages the pool behind it. This architecture is called backconnect. An HTTPS request takes the following path:

  1. The client connects to the gateway. Your script opens a TCP connection to a fixed endpoint such as pr.proxynet.io:8000.
  2. Credentials and parameters are read. The gateway verifies the user:pass pair in the Proxy-Authorization header. Preferences such as country, city and session ID are read at this stage too, from parameters appended to the username. The two authentication methods are in Proxy Authentication: User:Pass vs IP Whitelist.
  3. The pool is filtered. If you gave a location target, the gateway treats only the exits that match it as candidates. Rotation happens inside this subset.
  4. An exit node is chosen. Depending on the rotation mode, either a new exit is assigned or the exit already bound to your session is reused. This is the step that separates the three rotation modes.
  5. The tunnel is set up. The gateway connects to the target through the chosen exit and returns 200 Connection Established to the client. The TLS handshake happens after that, between the client and the target site.
  6. Traffic is relayed. The target site sees the request as coming from the exit node's IP. Neither the gateway's address nor yours reaches the target.

The first lines the client sends to the gateway look like this:

text
CONNECT example.com:443 HTTP/1.1
Host: example.com:443
Proxy-Authorization: Basic dXNlcjpwYXNz

The CONNECT method is defined in section 9.3.6 of RFC 9110, and an important detail hides here: once the tunnel is up, the proxy only carries bytes. It cannot see the individual HTTPS requests passing through. The exit IP is chosen while the tunnel is being set up and does not change as long as the tunnel stays open. That is why "a new IP on every request" in practice means "a new IP on every new connection". With unencrypted HTTP the proxy sees each request separately, so a true per-request change is possible there; but since most sites run on HTTPS today, treat the connection as the unit.

Three rotation modes: per request, timed and sticky session

The modes differ in which event triggers the "new exit or old exit" decision in step four.

Per-request rotation

Every new connection opened to the gateway gets a different exit from the pool. The client keeps no state, and the gateway remembers nothing on your behalf. This is the mode for jobs that collect many independent pages: each product page is a single request and the next one does not need to come from the same address. The cost is a fresh TCP and TLS handshake on every request; latency rises compared with a setup that reuses connections.

Timed rotation

The exit IP changes at a set interval. Until the interval runs out, every connection you open leaves from the same address; when it runs out, they all move to the new address together. The trigger is the clock, not your requests. It is common on mobile proxy ports that run on a single modem or device: the IP is renewed when the device reconnects to the carrier network. Setup is simple, but you cannot choose where in your job the change will fall.

Sticky session

You append a session ID to the username. Connections that arrive with the same ID are bound to the same exit, different IDs to different exits. How long the session is held on the same IP is selected in the dashboard, anywhere from 1 to 60 minutes; when the time runs out, or when you change the ID, the gateway assigns a new exit. The difference from timed rotation is that you do the grouping: give each of twenty parallel jobs its own ID and each one runs side by side with its own fixed address. This is the mode for jobs where the server keeps state, such as logged-in dashboards, cart flows and pagination. The product side is on the Sticky Proxy page.

There is one limit: in residential and mobile pools the exit node is a real device and it can leave the network. The gateway then moves the session to another exit before the time is up. A sticky session means "try to hold the same IP for this long", not a guarantee. For work that needs strict continuity, use Static Proxy, where the address is allocated to you.

Per requestTimedSticky sessionStatic (for comparison)
Event that changes the IPEvery new connectionThe interval running outThe session ID changing or the time running outDoes not change
Who is in controlThe gatewayThe clockYouNobody
Stateful flowsBreakBreak at the moment of changePreservedPreserved
In parallel jobsA separate IP per connectionAll on the same IPA separate IP per IDAs many as the IPs you hold
Typical jobBulk reading of independent pagesSingle-device mobile portLogin, cart, paginationAPI allowlist, long-lived account

Terms: rotating proxy, backconnect, sticky and the rest

The terms get mixed up because the same thing goes by several names and different things share one name. "Rotating proxy", "rotating IP proxy" and "backconnect rotating proxy" in vendor pages refer to the same product.

TermWhat it describesWhat it is often confused with
IP rotation / proxy rotationThe process: the exit IP changing within a poolTaken for the name of the product
Rotating proxyThe product: a proxy service that rotates at the gatewayA proxy list
BackconnectThe architecture: one endpoint, a pool behind itTaken for a separate proxy type; it is how a rotating proxy works
GatewayThe host:port you connect to; the server that picks the exitThe exit IP. The target site does not see the gateway's address
Exit node / exit IPThe address the target site seesThe gateway's address
IP poolThe set of addresses the gateway picks fromAddresses that belong to you. The pool is shared
Sticky sessionThe same session ID staying bound to the same exit for a whileA static IP. Sticky is temporary
Static proxyAn unchanging address allocated to youA long sticky session
Proxy listA fixed set of addresses you rotate with your own codeA rotating proxy

One caveat: searching for "sticky session" also brings up load balancer documentation. There the term describes a visitor always being routed to the same backend server. The logic is the same, the direction is reversed: a load balancer pins incoming traffic, a proxy pins outgoing traffic.

Should your code rotate, or the gateway?

If you hold a list of fixed addresses that belong to you, your code does the rotation: before each request it picks the next address in the list or a random one. Sequential selection splits the load evenly; random selection does not require a shared counter between jobs running in parallel. Removing an address that stops responding and limiting the rate per address is also up to you. We gave the Python code for both methods, step by step with Requests, in How to Rotate Proxies in Python; we are not rewriting it here.

In the gateway model all of this moves to the other side. A single proxy address remains in your code and the rotation mode is chosen with parameters in the username. In return, you do not know the addresses one by one: you cannot tell in advance which IP the next request will leave from, you only set its country, its city and the session behaviour. For a small job that runs on a few addresses a list is enough; as the pool grows, maintaining the list takes more time than the job itself.

Why did the IP not change? Connection reuse

The most common reason you keep seeing the same IP with per-request rotation on is not the proxy but your client. In HTTP/1.1 connections are persistent by default (RFC 9112, 9.3): after receiving a response the client keeps the same TCP connection open for the next request. Behind a proxy this means the same CONNECT tunnel is reused. Because the tunnel's exit is chosen when it is set up, the gateway never gets a moment to rotate.

More clients reuse connections than you might guess. In Python Requests the Session object does it by itself; the Requests documentation says keep-alive is automatic within a session. Client in HTTPX, ClientSession in AIOHTTP, agents with keep-alive enabled in Node.js and every browser behave the same way. The library differences are in HTTPX vs. Requests vs. AIOHTTP Compared.

What to do depends on what you want:

  • If you want a new IP on every request, open a new connection for each request or add a Connection: close header to the request. The target closes the connection after the response and the tunnel closes with it. You accept the cost of a new handshake every time.
  • If you want to stay on the same IP, do not rely on keep-alive. The connection can drop through a timeout, on the server side or during a retry, and a new connection brings a new IP. Build continuity with a session ID, that is, a sticky session.
  • In browser automation a single page opens many parallel connections to download its resources. With per-request rotation the HTML of one page is requested from one address and its images from others. Use a sticky session when working with a browser; the setup is in What Is Playwright and How to Use It With a Proxy.

Verifying rotation: three requests in a row

The way to see that your setup behaves as expected is to send a few requests in a row to a service that returns your exit IP as the response. The example below sends the same three requests in two ways: first with a new connection each time, then through a single Session.

python
import requests

PROXY = "http://user:pass@pr.proxynet.io:8000"
PROXIES = {"http": PROXY, "https": PROXY}
IP_ECHO = "https://api.ipify.org"


def new_connection_each_time(count=3):
    ips = []
    for _ in range(count):
        # Call without a session: each request opens and closes its own connection
        response = requests.get(IP_ECHO, proxies=PROXIES, timeout=20)
        ips.append(response.text.strip())
    return ips


def shared_session(count=3):
    ips = []
    with requests.Session() as session:
        session.proxies.update(PROXIES)
        for _ in range(count):
            # Same session: the tunnel opened by the first request is reused
            response = session.get(IP_ECHO, timeout=20)
            ips.append(response.text.strip())
    return ips


def report(label, ips):
    print(f"{label}: {ips} -> {len(set(ips))} distinct IPs")


report("new connection each time", new_connection_each_time())
report("shared session (keep-alive)", shared_session())

On a gateway that rotates per request the expected output looks like this (the addresses come from the example ranges reserved for documentation):

text
new connection each time: ['203.0.113.24', '198.51.100.7', '203.0.113.181'] -> 3 distinct IPs
shared session (keep-alive): ['198.51.100.92', '198.51.100.92', '198.51.100.92'] -> 1 distinct IPs

When we tried the example on a local test proxy, the proxy log showed the first function opening three separate CONNECT tunnels and the second opening a single one; once a Connection: close header was added to the Session, the tunnel count went back up to three. If you see a single IP on the first line as well, you are connecting with a sticky username or a static address. To also check the country of the exit IP and any leaks, see Is My Proxy Working? How to Test a Proxy.

How does a rotating mobile proxy work?

"Rotating mobile proxy" brings a desk full of phones to mind, but the actual mechanism lives in the carrier's network. Mobile carriers share one public IPv4 address among many subscribers at the same time (CGNAT); when a device reconnects to the network it can receive a different address from the carrier's pool. Mobile proxy rotation relies on this behaviour: either a single device reconnects at set intervals (timed rotation) or the gateway picks among many devices. How CGNAT works is covered in What Is CGNAT? How to Check and Get Out of It.

This has two practical consequences. First, a mobile exit IP is shared with real subscribers at that moment; using the address heavily affects them as well as you, so in a mobile pool a low request rate is not a courtesy but a requirement. Second, in a mobile pool a "new IP" does not always mean an address you have not seen before: the carrier's pool is limited and the same address can come back to you. The product side is on the Mobile Proxy page.

What rotation breaks

A few things break silently when rotation is switched on. What they have in common is that the server also recognises you by something other than the IP.

  • Cookie and IP out of step. Your cookie jar stays the same while the IP changes on every request. The site sees the same session cookie from different cities within minutes; its security logic closes the session or asks you to verify again. The rule is simple: one cookie jar, one session ID, one IP. The design for jobs that log in with your own account is in Login, Sessions and Cookies in Python.
  • A session that drops in the middle of pagination. Search results and filtered lists often depend on state held on the server (a cursor, a search session). If the IP changes on page five, the site may send you back to page one or serve the same records again; the data comes out incomplete or duplicated and you see no error code. Details are in Pagination in Web Scraping.
  • Rotation without a location target. If you set no target you rotate across the whole pool: one request leaves from Germany, the next from Brazil. Prices arrive in different currencies and pages in different languages, and the data you collect cannot be compared with itself.
  • Counters that are not tied to the IP. If the rate limit is counted per account, per cookie or per API key, rotation changes nothing. What to do on which code is collected in HTTP Status Codes in Web Scraping.

Use cases

  • Price and stock tracking across many sites. Each product page is an independent request; the country is pinned and the mode is per request. The design is on our price monitoring solution page, the methods are in How to Track Competitor Prices in E-Commerce.
  • Collecting public catalogues and listings. Low concurrency per site, rotation to spread the load: data scraping solution.
  • Checking how things look from a location. To check how an ad, a price or a page looks from a particular city over home connections, use Residential Proxy.
  • Dashboards you work in with your own accounts. One session ID per account and the same IP for the length of that session: sticky session.
  • APIs that require an IP allowlist. If the other side is going to add your address to its list, rotation is no use; the address must not change: Static IP for API Access.

Common mistakes

  • Expecting per-request rotation with a Session. The session reuses the connection; the IP stays the same until the tunnel closes.
  • Giving every parallel job the same session ID. They all pile onto one IP and the load-spreading benefit of rotation is lost.
  • Using rotation in place of a rate limit. The address changes but the total load on the target is the same; a per-site concurrency limit and delays are still needed.
  • Retrying immediately on a new IP. Resending without waiting after a 429 or a 503 ignores the slowdown the server asked for.

Decision guide

NeedRecommendation
Many independent public pagesPer-request rotation, country pinned
Login, cart or multi-step formSticky session, one ID per flow
A long list crawled through paginationSticky session; change the ID when the list is done
Browser automation (Playwright, Selenium)Sticky session, one ID per browser profile
Independent accounts running at the same timeA separate session ID per account
IP allowlist, one long-lived identityStatic proxy
You hold a few fixed addressesList rotation in your code
The site returns 429Not rotation: wait and lower the rate

Frequently asked questions

Are IP rotation and a rotating proxy the same thing?

One is a process, the other a product. IP rotation is the act of changing the exit address, and you can do it in your own code with a proxy list too. A rotating proxy is the service that does this for you at the gateway.

Is a backconnect proxy a separate proxy type?

No. Backconnect is the name of an architecture: you connect to a single endpoint and the gateway picks the exit from the pool behind it. Residential and mobile rotating proxy services work this way. The type of the IP (home connection, mobile, data center) is set by the source of the pool, not by backconnect; the difference between the types is in ISP vs Residential Proxies.

Why does the IP not change on every request when rotation is on?

Most likely your client is reusing the same connection. With HTTPS the exit IP is chosen while the CONNECT tunnel is being set up and does not change while the tunnel stays open. Open a new connection for each request or send a Connection: close header. Also check whether a sticky session parameter is left in your username.

How long does a sticky session last?

You select the duration in the dashboard, anywhere from 1 to 60 minutes, and you can move to a new IP whenever you like by changing the session ID. The duration is an upper limit, not a guarantee: if the exit node leaves the network, the gateway moves the session to another address earlier. Write your code so that it restarts the flow if the IP changes in the middle of a session.

Does rotation make rate limits irrelevant?

No. Rotation reduces the load per address, not the total load on the target server. A per-site concurrency limit, delays between requests and honouring the Retry-After header are still needed with rotation.

How many IPs do you need for rotation?

There is no single right number; the calculation starts from the request rate per address. In the gateway model you do not have to do this calculation because you are not buying addresses: you rotate across the whole pool and billing is mostly based on traffic. The selection criteria are in What to Look for When Buying a Proxy.

Summary

IP rotation is the changing of the exit address within a pool, and the gateway makes the decision: on every new connection, when the time runs out or when the session ID changes. Because with HTTPS the exit is chosen when the tunnel is set up, "per-request" rotation is really per connection; a client that reuses its connection stays on the same IP. Choose per-request rotation for independent pages, a sticky session for stateful flows and a static address for identities that must not change, and always state the country explicitly. Rotation does not replace a rate limit; it spreads the load, and a respectful crawl rate is still required. You can compare the types that fit your work in our proxy services.

Ask ChatGPTAsk Claude