Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
CHANGELOG
=========

5.2.0 (unreleased)
------------------

* A new `residential` field has been added to the `Anonymizer` record. This
is an `AnonymizerFeed` record containing `confidence`, `networkLastSeen`,
and `providerName` fields with residential proxy data for the network.
`residential` may be populated even when none of the other fields on
`Anonymizer` are set. The `AnonymizerFeed` record is intended to be reused
for additional feeds, such as VPNs, mobile networks, and hosting or
datacenter providers, that may be added in the future.

5.1.0 (2026-05-12)
------------------

Expand Down
61 changes: 59 additions & 2 deletions src/main/java/com/maxmind/geoip2/record/Anonymizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
* @param providerName The name of the VPN provider (e.g., NordVPN, SurfShark, etc.) associated
* with the network. This is only available from the GeoIP Insights
* web service.
* @param residential Residential proxy data for the network. This may be populated even when
* none of the other fields on this record are set. This is only available
* from the GeoIP Insights web service.
*/
public record Anonymizer(
@JsonProperty("confidence")
Expand Down Expand Up @@ -58,14 +61,68 @@ public record Anonymizer(
LocalDate networkLastSeen,

@JsonProperty("provider_name")
String providerName
String providerName,

@JsonProperty("residential")
AnonymizerFeed residential
) implements JsonSerializable {

/**
* Compact canonical constructor that sets a default for a null {@code residential} value.
*/
public Anonymizer {
residential = residential != null ? residential : new AnonymizerFeed();
}

/**
* Constructs an {@code Anonymizer} record with {@code null} values for all the nullable
* fields and {@code false} for all boolean fields.
*/
public Anonymizer() {
this(null, false, false, false, false, false, false, null, null);
this(null, false, false, false, false, false, false, null, null, null);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

/**
* Constructs an {@code Anonymizer} record without the {@code residential} field.
*
* @param confidence the confidence that the network is an actively used VPN service
* @param isAnonymous whether the IP address belongs to any sort of anonymous network
* @param isAnonymousVpn whether the IP address is registered to an anonymous VPN provider
* @param isHostingProvider whether the IP address belongs to a hosting or VPN provider
* @param isPublicProxy whether the IP address belongs to a public proxy
* @param isResidentialProxy whether the IP address is on a suspected anonymizing network
* and belongs to a residential ISP
* @param isTorExitNode whether the IP address is a Tor exit node
* @param networkLastSeen the last day that the network was sighted in our analysis of
* anonymized networks
* @param providerName the name of the VPN provider associated with the network
* @deprecated Use the canonical constructor that also accepts the {@code residential}
* field. This constructor is provided for backward compatibility and will be
* removed in version 6.0.0.
*/
@Deprecated(since = "5.2.0", forRemoval = true)
public Anonymizer(
Integer confidence,
boolean isAnonymous,
boolean isAnonymousVpn,
boolean isHostingProvider,
boolean isPublicProxy,
boolean isResidentialProxy,
boolean isTorExitNode,
LocalDate networkLastSeen,
String providerName
) {
this(
confidence,
isAnonymous,
isAnonymousVpn,
isHostingProvider,
isPublicProxy,
isResidentialProxy,
isTorExitNode,
networkLastSeen,
providerName,
null
);
}
}
43 changes: 43 additions & 0 deletions src/main/java/com/maxmind/geoip2/record/AnonymizerFeed.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.maxmind.geoip2.record;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.maxmind.geoip2.JsonSerializable;
import java.time.LocalDate;

/**
* <p>
* Contains data for one type of anonymizer detection, currently residential proxies. Additional
* feeds, such as VPNs, mobile networks, and hosting or datacenter providers, may be added to the
* {@link Anonymizer} record in the future using this same record type.
* </p>
* <p>
* This record is returned by the GeoIP Insights web service.
* </p>
*
* @param confidence A score ranging from 1 to 99 that represents our percent confidence that
* the network is an actively used residential proxy. This is only available
* from the GeoIP Insights web service.
* @param networkLastSeen The last day that the network was sighted in our analysis of
* residential proxies. This is only available from the GeoIP Insights
* web service.
* @param providerName The name of the residential proxy provider associated with the network.
* This is only available from the GeoIP Insights web service.
*/
public record AnonymizerFeed(
@JsonProperty("confidence")
Integer confidence,

@JsonProperty("network_last_seen")
LocalDate networkLastSeen,

@JsonProperty("provider_name")
String providerName
) implements JsonSerializable {

/**
* Constructs an {@code AnonymizerFeed} record with {@code null} values for all fields.
*/
public AnonymizerFeed() {
this(null, null, null);
}
}
20 changes: 20 additions & 0 deletions src/test/java/com/maxmind/geoip2/model/InsightsResponseTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import com.maxmind.geoip2.exception.GeoIp2Exception;
import com.maxmind.geoip2.model.ConnectionTypeResponse.ConnectionType;
import com.maxmind.geoip2.record.Anonymizer;
import com.maxmind.geoip2.record.AnonymizerFeed;
import com.maxmind.geoip2.record.Location;
import com.maxmind.geoip2.record.MaxMind;
import com.maxmind.geoip2.record.Postal;
Expand Down Expand Up @@ -206,6 +207,25 @@ public void testAnonymizer() {
anonymizer.providerName(),
"anonymizer.providerName() does not return NordVPN"
);

AnonymizerFeed residential = anonymizer.residential();

assertNotNull(residential, "anonymizer.residential() returns null");
assertEquals(
Integer.valueOf(82),
residential.confidence(),
"anonymizer.residential().confidence() does not return 82"
);
assertEquals(
LocalDate.parse("2026-05-11"),
residential.networkLastSeen(),
"anonymizer.residential().networkLastSeen() does not return 2026-05-11"
);
assertEquals(
"quickshift",
residential.providerName(),
"anonymizer.residential().providerName() does not return quickshift"
);
}

@Test
Expand Down
5 changes: 5 additions & 0 deletions src/test/java/com/maxmind/geoip2/model/JsonTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ public void testInsightsSerialization() throws IOException {
.put("is_tor_exit_node", true)
.put("network_last_seen", "2024-12-31")
.put("provider_name", "NordVPN")
.startObjectField("residential")
.put("confidence", 82)
.put("network_last_seen", "2026-05-11")
.put("provider_name", "quickshift")
.end()
.end()
.startObjectField("country")
.startObjectField("names")
Expand Down
7 changes: 6 additions & 1 deletion src/test/resources/test-data/insights0.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@
"is_residential_proxy": true,
"is_tor_exit_node": true,
"network_last_seen": "2024-12-31",
"provider_name": "NordVPN"
"provider_name": "NordVPN",
"residential": {
"confidence": 82,
"network_last_seen": "2026-05-11",
"provider_name": "quickshift"
}
}
}
7 changes: 6 additions & 1 deletion src/test/resources/test-data/insights1.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@
"is_residential_proxy": true,
"is_tor_exit_node": true,
"network_last_seen": "2024-12-31",
"provider_name": "NordVPN"
"provider_name": "NordVPN",
"residential": {
"confidence": 82,
"network_last_seen": "2026-05-11",
"provider_name": "quickshift"
}
}
}
Loading