Skip to content

Commit 66aab25

Browse files
oschwaldclaude
andcommitted
Add residential proxy data to anonymizer object
This adds a new residential sub-object to the anonymizer object in the GeoIP2 Insights web service response. It is sourced from the full-feed GeoIP Residential Proxy database and includes confidence scoring, provider name detection, and network last seen date for residential proxies. Because the residential proxy feed is a superset of what is covered by Anonymous Plus, the anonymizer object may now contain only the residential key. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 537148d commit 66aab25

4 files changed

Lines changed: 85 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## 1.6.0
4+
5+
* A new `residential` object has been added to the `anonymizer` object on
6+
`MaxMind::GeoIP2::Model::Insights`. This object contains data from the
7+
GeoIP Residential Proxy database, including confidence scoring, provider
8+
name detection, and network last seen date for residential proxies. This
9+
is only available from the GeoIP2 Insights web service.
10+
311
## 1.5.1 (2026-01-19)
412

513
* Re-release with a fix to the release process. This includes a bump of the

lib/maxmind/geoip2/record/anonymizer.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
require 'date'
44
require 'maxmind/geoip2/record/abstract'
5+
require 'maxmind/geoip2/record/anonymizer_feed'
56

67
module MaxMind
78
module GeoIP2
@@ -11,6 +12,20 @@ module Record
1112
#
1213
# This record is returned by the Insights web service.
1314
class Anonymizer < Abstract
15+
# Data about the residential proxy status of the IP address, as
16+
# sourced from the GeoIP Residential Proxy database. This property is
17+
# only available from Insights.
18+
#
19+
# @return [MaxMind::GeoIP2::Record::AnonymizerFeed]
20+
attr_reader :residential
21+
22+
# @!visibility private
23+
def initialize(record)
24+
super
25+
26+
@residential = AnonymizerFeed.new(record.nil? ? nil : record['residential'])
27+
end
28+
1429
# A score ranging from 1 to 99 that represents our percent confidence
1530
# that the network is currently part of an actively used VPN service.
1631
# This property is only available from Insights.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# frozen_string_literal: true
2+
3+
require 'date'
4+
require 'maxmind/geoip2/record/abstract'
5+
6+
module MaxMind
7+
module GeoIP2
8+
module Record
9+
# Contains data from an anonymizer data feed, such as the residential
10+
# proxy feed.
11+
#
12+
# This record is returned by the anonymizer object of the Insights web
13+
# service.
14+
class AnonymizerFeed < Abstract
15+
# A score ranging from 1 to 99 that represents our percent confidence
16+
# that the network is currently part of this anonymizer feed. This
17+
# property is only available from Insights.
18+
#
19+
# @return [Integer, nil]
20+
def confidence
21+
get('confidence')
22+
end
23+
24+
# The last day that the network was sighted in this anonymizer feed.
25+
# This value is parsed lazily. This property is only available from
26+
# Insights.
27+
#
28+
# @return [Date, nil] A Date object representing the last seen date,
29+
# or nil if the date is not available.
30+
def network_last_seen
31+
return @network_last_seen if defined?(@network_last_seen)
32+
33+
date_string = get('network_last_seen')
34+
35+
if !date_string
36+
return nil
37+
end
38+
39+
@network_last_seen = Date.parse(date_string)
40+
end
41+
42+
# The name of the provider associated with the network in this
43+
# anonymizer feed. This property is only available from Insights.
44+
#
45+
# @return [String, nil]
46+
def provider_name
47+
get('provider_name')
48+
end
49+
end
50+
end
51+
end
52+
end

test/test_client.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ class ClientTest < Minitest::Test
3838
'is_tor_exit_node' => false,
3939
'network_last_seen' => '2025-10-15',
4040
'provider_name' => 'nordvpn',
41+
'residential' => {
42+
'confidence' => 82,
43+
'network_last_seen' => '2026-05-11',
44+
'provider_name' => 'quickshift',
45+
},
4146
},
4247
'continent' => {
4348
'code' => 'NA',
@@ -109,6 +114,11 @@ def test_insights
109114
assert_equal(Date.parse('2025-10-15'), record.anonymizer.network_last_seen)
110115
assert_equal('nordvpn', record.anonymizer.provider_name)
111116

117+
# Test anonymizer.residential object
118+
assert_equal(82, record.anonymizer.residential.confidence)
119+
assert_equal(Date.parse('2026-05-11'), record.anonymizer.residential.network_last_seen)
120+
assert_equal('quickshift', record.anonymizer.residential.provider_name)
121+
112122
# Test traits
113123
assert(record.traits.anycast?)
114124
assert(record.traits.residential_proxy?)

0 commit comments

Comments
 (0)