# 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.

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](https://krebsonsecurity.com/2026/07/lg-to-ban-residential-proxies-from-smart-tv-apps/)). 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](https://www.ic3.gov/PSA/2026/PSA260312)).

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 addresses | IPv6 addresses | IPv6 /64s |
|---|---:|---:|---:|
| Seen in a pool | 69,082,965 | 48,760,485 | 21,194,839 |
| Still seen a day after the first sighting | 59.3% | 5.0% | 27.0% |
| A week after | 47.8% | 1.0% | 14.4% |
| A month after | 39.2% | 0.2% | 7.9% |
| Two months after | 32.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](https://docs.vpndetection.io/integrations/nodejs):

```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](https://vpndetection.io/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](https://vpndetection.io/databases/residential-proxy-ip), which carries the same fields, instead of calling the [API](https://vpndetection.io/api) per request.

