Skip to content

Commit 305c0ed

Browse files
authored
Merge pull request #740 from maxmind/greg/stf-997-add-residential-to-anonymizer
Add residential proxy data to Anonymizer record
2 parents 33b6ceb + c468a20 commit 305c0ed

7 files changed

Lines changed: 152 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
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 with residential proxy data for the network.
10+
`residential` may be populated even when none of the other fields on
11+
`Anonymizer` are set. The `AnonymizerFeed` record is intended to be reused
12+
for additional feeds, such as VPNs, mobile networks, and hosting or
13+
datacenter providers, that may be added in the future.
14+
415
5.1.0 (2026-05-12)
516
------------------
617

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

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
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 Residential proxy data for the network. This may be populated even when
35+
* none of the other fields on this record are set. This is only available
36+
* from the GeoIP Insights web service.
3437
*/
3538
public record Anonymizer(
3639
@JsonProperty("confidence")
@@ -58,14 +61,69 @@ public record Anonymizer(
5861
LocalDate networkLastSeen,
5962

6063
@JsonProperty("provider_name")
61-
String providerName
64+
String providerName,
65+
66+
@JsonProperty("residential")
67+
AnonymizerFeed residential
6268
) implements JsonSerializable {
6369

70+
/**
71+
* Compact canonical constructor that sets a default for a null {@code residential} value.
72+
*/
73+
public Anonymizer {
74+
residential = residential != null ? residential : new AnonymizerFeed();
75+
}
76+
6477
/**
6578
* Constructs an {@code Anonymizer} record with {@code null} values for all the nullable
66-
* fields and {@code false} for all boolean fields.
79+
* fields and {@code false} for all boolean fields. The {@code residential} field defaults
80+
* to an empty {@code AnonymizerFeed} rather than {@code null}.
6781
*/
6882
public Anonymizer() {
69-
this(null, false, false, false, false, false, false, null, null);
83+
this(null, false, false, false, false, false, false, null, null, null);
84+
}
85+
86+
/**
87+
* Constructs an {@code Anonymizer} record without the {@code residential} field.
88+
*
89+
* @param confidence the confidence that the network is an actively used VPN service
90+
* @param isAnonymous whether the IP address belongs to any sort of anonymous network
91+
* @param isAnonymousVpn whether the IP address is registered to an anonymous VPN provider
92+
* @param isHostingProvider whether the IP address belongs to a hosting or VPN provider
93+
* @param isPublicProxy whether the IP address belongs to a public proxy
94+
* @param isResidentialProxy whether the IP address is on a suspected anonymizing network
95+
* and belongs to a residential ISP
96+
* @param isTorExitNode whether the IP address is a Tor exit node
97+
* @param networkLastSeen the last day that the network was sighted in our analysis of
98+
* anonymized networks
99+
* @param providerName the name of the VPN provider associated with the network
100+
* @deprecated Use the canonical constructor that also accepts the {@code residential}
101+
* field. This constructor is provided for backward compatibility and will be
102+
* removed in version 6.0.0.
103+
*/
104+
@Deprecated(since = "5.2.0", forRemoval = true)
105+
public Anonymizer(
106+
Integer confidence,
107+
boolean isAnonymous,
108+
boolean isAnonymousVpn,
109+
boolean isHostingProvider,
110+
boolean isPublicProxy,
111+
boolean isResidentialProxy,
112+
boolean isTorExitNode,
113+
LocalDate networkLastSeen,
114+
String providerName
115+
) {
116+
this(
117+
confidence,
118+
isAnonymous,
119+
isAnonymousVpn,
120+
isHostingProvider,
121+
isPublicProxy,
122+
isResidentialProxy,
123+
isTorExitNode,
124+
networkLastSeen,
125+
providerName,
126+
null
127+
);
70128
}
71129
}
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 for one type of anonymizer detection, currently residential proxies. Additional
10+
* feeds, such as VPNs, mobile networks, and hosting or datacenter providers, may be added to the
11+
* {@link Anonymizer} record in the future using this same record type.
12+
* </p>
13+
* <p>
14+
* This record is returned by the GeoIP Insights web service.
15+
* </p>
16+
*
17+
* @param confidence A score ranging from 1 to 99 that represents our percent confidence that
18+
* the network is currently part of this anonymizer feed. This is only
19+
* available from the GeoIP Insights web service.
20+
* @param networkLastSeen The last day that the network was sighted in our analysis of this
21+
* anonymizer feed. This is only available from the GeoIP Insights web
22+
* service.
23+
* @param providerName The name of the provider associated with the network in this anonymizer
24+
* feed. 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)