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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
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 sourced from the GeoIP Residential Proxy feed.
Because the residential proxy feed is a superset of the data used for the
other `Anonymizer` fields, `residential` may be populated even when none of
the other fields on `Anonymizer` are set. The `AnonymizerFeed` record is
intended to be reused for other anonymizer network categories that may be
added in the future.

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

Expand Down
63 changes: 61 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,11 @@
* @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 Data about the network's presence in the GeoIP Residential Proxy feed.
* Note that the residential proxy feed is a superset of the data used for
* the other fields on this record, so this field may be present even when
* none of the other fields are set. This is only available from the GeoIP
* Insights web service.
*/
public record Anonymizer(
@JsonProperty("confidence")
Expand Down Expand Up @@ -58,14 +63,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 about a network's presence in a specific anonymizer data feed, such as the
* residential proxy feed. 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 is our percent confidence that the
* network is currently part of an actively used network of this feed's
* category. This is only available from the GeoIP Insights web service.
* @param networkLastSeen The last day that the network was sighted in this feed. This is only
* available from the GeoIP Insights web service.
* @param providerName The name of the provider (e.g., NordVPN, SurfShark, etc.) 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