Skip to content
VPNDetection

How long do residential proxy IPs last? 90 days of pool data

How long IPv4 and IPv6 addresses stay in residential proxy pools, from 90 days of our data, and a decaying score to use in place of a block.

Published 3 min read

On this page
  1. How long an address stays in a pool
  2. Why a fixed block time doesn't fit
  3. A score that decays from the last sighting

Residential proxies spent the summer in the news. In June, researchers found residential proxy SDKs in over 42% of the apps on LG's webOS TV app store, and within a month LG said it would suspend any app that didn't remove one (Krebs on Security). The FBI had already warned in March that apps, free VPNs and pirated software enroll devices in these networks, and called residential proxies "a standard tool criminals use to look like ordinary users online" (IC3).

A residential proxy network sells the use of home internet connections. Software on a phone, a TV or a streaming box relays other people's traffic, so a scraper's or a fraudster's requests leave from a household's IP address, and a site sees the household.

When one of those addresses turns up at a signup form or a checkout, the question is how long to keep treating it as a proxy. Here's what our last 90 days of residential proxy data says.

How long an address stays in a pool

We took every address seen in a residential proxy pool from June 30 to September 27, 2026, and measured how long after its first sighting it was still being seen.

IPv4 addressesIPv6 addressesIPv6 /64s
Seen in a pool69,082,96548,760,48521,194,839
Still seen a day after the first sighting59.3%5.0%27.0%
A week after47.8%1.0%14.4%
A month after39.2%0.2%7.9%
Two months after32.8%0.1%5.7%

Each share counts only the addresses we first saw early enough in the window to be seen that much later. Still seen means seen again at least that long after the first sighting, not seen every day in between.

The 48.8 million IPv6 addresses came from 21.2 million /64s, 2.3 addresses each. A /64 is normally one home network or one phone. 62.5% of the IPv4 addresses and 14.1% of the IPv6 ones were in more than one proxy network's pool.

Why a fixed block time doesn't fit

A 24-hour block lets the IPv4 addresses that stay for months back in while they're still for rent. A permanent ban keeps refusing the ones that left within a day, and those are households' addresses, which ISPs reassign to other households.

Blocking an IPv6 address does nothing, since it's almost never seen again. Blocking its /64 catches the next address from the same network, and every other device on that network with it.

A score that decays from the last sighting

What fits both is a score, not a block. It's 1 when an address is seen in a pool, and it halves every few days after its last sighting. An address that stays in a pool keeps being seen, so its score stays near 1 for as long as it's for rent, and one that has left fades out without anyone unblocking it. For IPv6, keep the score on the /64, so the next address from the same network inherits it.

The half-lives come from the table: about half of new IPv4 addresses are gone within a week, and most IPv6 /64s within a day.

Look the address up when it matters, at signup, login or payment, rather than caching a verdict for weeks. With the Node.js library:

js
import { isIPv4 } from 'node:net';
import { VPNDetection } from 'vpndetection';

const client = new VPNDetection({ apiKey: process.env.VPNDETECTION_API_KEY });

const DAY_MS = 24 * 60 * 60 * 1000;
// Days after which a sighting counts for half as much.
const HALF_LIFE_DAYS = { v4: 7, v6: 1 };

// The last sighting in each IPv6 /64. A Map keeps the example short: use a
// store your servers share (Redis, a table), and drop entries after a week.
const lastSeenBy64 = new Map();

// 1 for an address in a residential proxy pool today, halving with every
// half-life since its last sighting, and 0 for one never seen.
export async function proxyScore(ip) {
    // A dual-stack server reports an IPv4 visitor as ::ffff:a.b.c.d.
    const addr = ip.replace(/^::ffff:(?=\d+\.\d+\.\d+\.\d+$)/i, '');
    const { isResproxy, resproxy } = await client.lookup(addr);
    // last_seen is a date, so count the address as seen until that day's end.
    let lastSeen = isResproxy ? Date.parse(resproxy.last_seen) + DAY_MS : 0;
    const v4 = isIPv4(addr);
    if (!v4) {
        const key = prefix64(addr);
        lastSeen = Math.max(lastSeen, lastSeenBy64.get(key) ?? 0);
        if (lastSeen > 0) {
            lastSeenBy64.set(key, lastSeen);
        }
    }
    if (lastSeen === 0) {
        return 0;
    }
    const idleDays = Math.max(0, Date.now() - lastSeen) / DAY_MS;
    return 0.5 ** (idleDays / (v4 ? HALF_LIFE_DAYS.v4 : HALF_LIFE_DAYS.v6));
}

// The first four groups of an IPv6 address, which name its /64.
function prefix64(ip) {
    const [head, tail] = ip.split('::');
    const groups = head ? head.split(':') : [];
    if (tail !== undefined) {
        const rest = tail ? tail.split(':') : [];
        groups.push(...Array(8 - groups.length - rest.length).fill('0'), ...rest);
    }
    return groups.slice(0, 4).map((g) => parseInt(g, 16).toString(16)).join(':');
}

The API answers for the address you ask about, not its /64, so the code keeps the /64s itself. On September 28, 2026, we ran it over six addresses from our data:

0.98  IPv4, in a pool since June 30, last seen September 27
0.98  the same address, as a dual-stack server reports it
0.05  IPv4, last seen in a pool on August 27
0.87  IPv6, seen in a pool once, on September 27
0.87  IPv6, another host in that /64
0.00  IPv4, an unflagged address in the same /24 as the first

The second IPv6 host isn't in any pool itself. It scores 0.87 because the first one put its /64 on record.

Use the score to decide how much to ask of a visitor, not whether to let them in:

js
if (await proxyScore(req.ip) >= 0.5) {
    // Ask for more: an email or SMS code, a CAPTCHA, 3-D Secure on a payment.
}

At 0.5, that's an IPv4 address seen in a pool in the last week, or an IPv6 /64 seen in the last day.

isResproxy and its last_seen need a plan that includes residential proxy data (pricing). On one that doesn't, isResproxy is undefined and the score is 0. Past a few million lookups a day, look addresses up locally from the residential proxy database, which carries the same fields, instead of calling the API per request.

Written by

  • Uman Shahzad

    Founder & CEO

    IP intelligence data expert for over 8 years, former lead engineer at IPinfo, Uman has pioneered many systems and practices used by IP data companies to operate at scale, provide high-quality data and offer the best developer experiences.

Get new posts by email

Or follow along in a feed reader.

RSS feed

Try it on your own traffic.

The detection these posts describe is one API call away, with SDKs for every major language.

00 · No key

Start without signing up.

Paste it into a terminal. No account needed. 1k daily allowance per user, answering ip and is_vpn.

curl "https://api.vpndetection.io/45.83.91.1"
{
"ip": "45.83.91.1",
"is_vpn": true
}
01 · Free key

Sign up and get 50,000 requests a month.

No card and no sales call: the key is issued on signup.
Every request flags VPN IPs.
Upgrade only when you outgrow the allowance.