Skip to content

Commit 3fa9d90

Browse files
oschwaldclaude
andcommitted
Add residential proxy data to Anonymizer record
Adds a residential field to the Anonymizer record, sourced from the GeoIP Residential Proxy feed. This data is exposed as a new reusable AnonymizerFeed record (confidence, networkLastSeen, providerName) so that future anonymizer feeds (e.g. VPN, mobile, datacenter) can share the same shape. Because the residential proxy feed is a superset of Anonymous Plus data, the anonymizer object may now contain only the residential field. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 33b6ceb commit 3fa9d90

7 files changed

Lines changed: 109 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
CHANGELOG
22
=========
33

4+
5.2.0 (unreleased)
5+
------------------
6+
7+
* A new `residential` field has been added to the `Anonymizer` record. This
8+
is an `AnonymizerFeed` record containing `confidence`, `networkLastSeen`,
9+
and `providerName` fields sourced from the GeoIP Residential Proxy feed.
10+
Because the residential proxy feed is a superset of the data used for the
11+
other `Anonymizer` fields, `residential` may be populated even when none of
12+
the other fields on `Anonymizer` are set. The `AnonymizerFeed` record is
13+
intended to be reused for other anonymizer network categories that may be
14+
added in the future.
15+
416
5.1.0 (2026-05-12)
517
------------------
618

src/main/java/com/maxmind/geoip2/record/Anonymizer.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
* @param providerName The name of the VPN provider (e.g., NordVPN, SurfShark, etc.) associated
3232
* with the network. This is only available from the GeoIP Insights
3333
* web service.
34+
* @param residential Data about the network's presence in the GeoIP Residential Proxy feed.
35+
* Note that the residential proxy feed is a superset of the data used for
36+
* the other fields on this record, so this field may be present even when
37+
* none of the other fields are set. This is only available from the GeoIP
38+
* Insights web service.
3439
*/
3540
public record Anonymizer(
3641
@JsonProperty("confidence")
@@ -58,14 +63,24 @@ public record Anonymizer(
5863
LocalDate networkLastSeen,
5964

6065
@JsonProperty("provider_name")
61-
String providerName
66+
String providerName,
67+
68+
@JsonProperty("residential")
69+
AnonymizerFeed residential
6270
) implements JsonSerializable {
6371

72+
/**
73+
* Compact canonical constructor that sets a default for a null {@code residential} value.
74+
*/
75+
public Anonymizer {
76+
residential = residential != null ? residential : new AnonymizerFeed();
77+
}
78+
6479
/**
6580
* Constructs an {@code Anonymizer} record with {@code null} values for all the nullable
6681
* fields and {@code false} for all boolean fields.
6782
*/
6883
public Anonymizer() {
69-
this(null, false, false, false, false, false, false, null, null);
84+
this(null, false, false, false, false, false, false, null, null, null);
7085
}
7186
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.maxmind.geoip2.record;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import com.maxmind.geoip2.JsonSerializable;
5+
import java.time.LocalDate;
6+
7+
/**
8+
* <p>
9+
* Contains data about a network's presence in a specific anonymizer data feed, such as the
10+
* residential proxy feed. Additional feeds, such as VPNs, mobile networks, and hosting or
11+
* datacenter providers, may be added to the {@link Anonymizer} record in the future using this
12+
* same record type.
13+
* </p>
14+
* <p>
15+
* This record is returned by the GeoIP Insights web service.
16+
* </p>
17+
*
18+
* @param confidence A score ranging from 1 to 99 that is our percent confidence that the
19+
* network is currently part of an actively used network of this feed's
20+
* category. This is only available from the GeoIP Insights web service.
21+
* @param networkLastSeen The last day that the network was sighted in this feed. This is only
22+
* available from the GeoIP Insights web service.
23+
* @param providerName The name of the provider (e.g., NordVPN, SurfShark, etc.) associated with
24+
* the network. This is only available from the GeoIP Insights web service.
25+
*/
26+
public record AnonymizerFeed(
27+
@JsonProperty("confidence")
28+
Integer confidence,
29+
30+
@JsonProperty("network_last_seen")
31+
LocalDate networkLastSeen,
32+
33+
@JsonProperty("provider_name")
34+
String providerName
35+
) implements JsonSerializable {
36+
37+
/**
38+
* Constructs an {@code AnonymizerFeed} record with {@code null} values for all fields.
39+
*/
40+
public AnonymizerFeed() {
41+
this(null, null, null);
42+
}
43+
}

src/test/java/com/maxmind/geoip2/model/InsightsResponseTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import com.maxmind.geoip2.exception.GeoIp2Exception;
1717
import com.maxmind.geoip2.model.ConnectionTypeResponse.ConnectionType;
1818
import com.maxmind.geoip2.record.Anonymizer;
19+
import com.maxmind.geoip2.record.AnonymizerFeed;
1920
import com.maxmind.geoip2.record.Location;
2021
import com.maxmind.geoip2.record.MaxMind;
2122
import com.maxmind.geoip2.record.Postal;
@@ -206,6 +207,25 @@ public void testAnonymizer() {
206207
anonymizer.providerName(),
207208
"anonymizer.providerName() does not return NordVPN"
208209
);
210+
211+
AnonymizerFeed residential = anonymizer.residential();
212+
213+
assertNotNull(residential, "anonymizer.residential() returns null");
214+
assertEquals(
215+
Integer.valueOf(82),
216+
residential.confidence(),
217+
"anonymizer.residential().confidence() does not return 82"
218+
);
219+
assertEquals(
220+
LocalDate.parse("2026-05-11"),
221+
residential.networkLastSeen(),
222+
"anonymizer.residential().networkLastSeen() does not return 2026-05-11"
223+
);
224+
assertEquals(
225+
"quickshift",
226+
residential.providerName(),
227+
"anonymizer.residential().providerName() does not return quickshift"
228+
);
209229
}
210230

211231
@Test

src/test/java/com/maxmind/geoip2/model/JsonTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ public void testInsightsSerialization() throws IOException {
6262
.put("is_tor_exit_node", true)
6363
.put("network_last_seen", "2024-12-31")
6464
.put("provider_name", "NordVPN")
65+
.startObjectField("residential")
66+
.put("confidence", 82)
67+
.put("network_last_seen", "2026-05-11")
68+
.put("provider_name", "quickshift")
69+
.end()
6570
.end()
6671
.startObjectField("country")
6772
.startObjectField("names")

src/test/resources/test-data/insights0.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@
9494
"is_residential_proxy": true,
9595
"is_tor_exit_node": true,
9696
"network_last_seen": "2024-12-31",
97-
"provider_name": "NordVPN"
97+
"provider_name": "NordVPN",
98+
"residential": {
99+
"confidence": 82,
100+
"network_last_seen": "2026-05-11",
101+
"provider_name": "quickshift"
102+
}
98103
}
99104
}

src/test/resources/test-data/insights1.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@
110110
"is_residential_proxy": true,
111111
"is_tor_exit_node": true,
112112
"network_last_seen": "2024-12-31",
113-
"provider_name": "NordVPN"
113+
"provider_name": "NordVPN",
114+
"residential": {
115+
"confidence": 82,
116+
"network_last_seen": "2026-05-11",
117+
"provider_name": "quickshift"
118+
}
114119
}
115120
}

0 commit comments

Comments
 (0)