Using the Geocoder gem to do IP Geolocation in Ruby
Geocoder is a well-maintained and popular Ruby gem available on Github. Among few other tools, it can be used to retrieve location from an IP address. Geocoder gem relies on an external API to provide the requested data. The list of supported API is available on their Github repository.
The tedious parts are obtaining a Key from your favorite API and configuring the gem, after which looking for an IP address location is very simple:
results = Geocoder.search("172.56.21.89")
results.first.coordinates
=> [30.267153, -97.7430608]
results.first.country
=> "United States"
The accuracy of the location you can obtain depends on your visitor's internet provider's infrastructure, as mentioned above, and the quality of the API you are using.
The downsides of the Geocoder gem
Geocoder does not know how to perform geolocation by itself. It is simply a proxy for using an external API.
As mentioned above, and depending on your choice's API service, it may be difficult to create a key and authorize your application. As an example, Google Cloud Console can be very confusing.
Setting up the localization in your Rails project via I18n
To translate all the string used by core Rails, you need only to install the rails-i18n gem, which provides the translation in more than a hundred languages. You can also write your own translation in the files located in the config/locales directory.
Add one of the following lines to your Gemfile:
gem 'rails-i18n', '~> 6.0.0' # For 6.0.0 or higher
gem 'rails-i18n', '~> 5.1' # For 5.0.x, 5.1.x and 5.2.x
gem 'rails-i18n', '~> 4.0' # For 4.0.x
gem 'rails-i18n', '~> 3.0' # For 3.x
Then update your bundle:
bundle update
You must then set up a mechanism that allows the controller to determine which locale to use for the current request. Here is the list of elements to consider:
- the locale is saved in the user's session,
- a user can manually change the locale if he prefers to use your site in another language
- the system falls back to the default locale.
You can implement this function in a before_action of all your controllers:
class ApplicationController < ActionController::Base
before_action :set_locale
protected def set_locale
I18n.locale = params[:locale] || # 1: use request parameter, if available
session[:locale] || # 2: use the value saved in iurrent session
I18n.default_locale # last: fallback to default locale
end
end
You also need to save the selected locale in the user's session:
class ApplicationController < ActionController::Base
before_action :set_locale
after_action :save_locale
protected def set_locale
I18n.locale = params[:locale] || # 1: use request parameter, if available
session[:locale] || # 2: use the value saved in iurrent session
I18n.default_locale # last: fallback to default locale
end
protected def save_locale
session[:locale] = I18n.locale
end
end
Add automatic locale detection with IP geolocation
One of the most convenient features for a website is to automatically detect new visitors' geographical location and display itself in the locality corresponding to their region. This can be implemented through geolocation.
To do so, it is possible to use the geoip gem, which searches through a database to match an IP address to its geographical location.
Install the geoip gem in your Gemfile:
gem 'geoip'
Then update your bundle:
bundle update
Download the geolocation database from the MaxMind website, and extract the files in your Rails directory.
You can then use the gem's API to obtain the geographical location of your visitor from their IP address:
require 'geoip'
maxmind_db_location = '/path/to/GeoLite2-City.mmdb'
ip_address = '173.194.112.35'
g = GeoIP.new maxmind_db_location
loc = g.city ip_address
puts loc.country_code
# => US
However, this is not the easiest method, mainly because it requires a lot of maintenance as you will have to regularly download every MaxMind database updates in order to keep your geolocation accurate. It may not contain all the information you need, such as whether the IP address is using a VPN or proxy service.
Using the free Abstract IP geolocation service (easier)
An even simpler alternative to Geocoder is the use of Abstract IP Geolocation API. It's a free, world-class API, extremely precise, and able to provide lots of details from an IP address, including city, region, country, GPS coordinates... You can even pair it with Abstract's timezone API to get even more granular data.
As for most API services, you will first have to create an account on the Abstract website, automatically providing you with the API key and giving you access to the documentation. Then you are already all set-up and ready to go!
At this stage, you can already test the API from your browser by opening a URL like the one below, replacing YOUR_API_KEY with the key you obtained from your account page in the Abstract website:
https://ipgeolocation.abstractapi.com/v1/?api_key=YOUR_API_KEY&ip_address=92.184.105.98
As a result, you will obtain multiple details about a location associated with this IP address. You can also try it with your own public IP address.
Now let's implement this in a formal Ruby way, using the Net::HTTP Ruby standard library:
require 'net/http'
require 'net/https'
def make_abstract_request
uri = URI('https://ipgeolocation.abstractapi.com/v1/?api_key=YOUR_API_KEY&ip_address=92.184.105.98')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
request = Net::HTTP::Get.new(uri)
response = http.request(request)
return response.body
rescue StandardError => error
puts "Error (#{ error.message })"
end
pp JSON.parse(make_abstract_request)
You can run this code in a ruby console. Here is the response you would get:
{
"ip_address": "92.184.105.98",
"city": "Daglan",
"city_geoname_id": 3021928,
"region": "Nouvelle-Aquitaine",
"region_iso_code": "NAQ",
"region_geoname_id": 11071620,
"postal_code": "24250",
"country": "France",
"country_code": "FR",
"country_geoname_id": 3017382,
"country_is_eu": true,
"continent": "Europe",
"continent_code": "EU",
"continent_geoname_id": 6255148,
"longitude": 1.19282,
"latitude": 44.7419,
"security": {
"is_vpn": false
},
"timezone": {
"name": "Europe/Paris",
"abbreviation": "CET",
"gmt_offset": 1,
"current_time": "11:52:28",
"is_dst": false
},
"flag": {
"emoji": "š«š·",
"unicode": "U+1F1EB U+1F1F7",
"png": "https://static.abstractapi.com/country-flags/FR_flag.png",
"svg": "https://static.abstractapi.com/country-flags/FR_flag.svg"
},
"currency": {
"currency_name": "Euros",
"currency_code": "EUR"
},
"connection": {
"autonomous_system_number": 3215,
"autonomous_system_organization": "Orange S.A.",
"connection_type": "Cellular",
"isp_name": "Orange S.A.",
"organizaton_name": "Internet OM"
}
}
Frequently Asked Questions
What is IP geolocation and why would I use it in a Rails app?
IP geolocation translates a visitor's IP address into geographical data such as country, city, coordinates, and timezone. In a Rails application, this lets you personalize content by region, auto-detect the user's locale, enforce geographic licensing rules, or comply with regulations like GDPR, all without asking the user to enter their location manually.
How do I use the Geocoder gem for IP geolocation in Rails?
Add the geocoder gem to your Gemfile and run bundle install, then call Geocoder.search("visitor_ip") to retrieve location data including coordinates. Geocoder relies on an external API, so you will need to obtain and configure an API key for the service you choose, such as Google Maps Platform, which adds setup overhead compared to simpler alternatives.
How do I call the Abstract IP Geolocation API from a Rails controller?
Use Ruby's built-in Net::HTTP library to make an HTTPS GET request to https://ipgeolocation.abstractapi.com/v1/?api_key=YOUR_KEY&ip_address=VISITOR_IP. You can retrieve the visitor's IP inside any Rails controller with request.ip. The API returns JSON with country, city, timezone, currency, and VPN detection data, requiring no local database or complex configuration.
What is the difference between the geoip gem and using an external API like Abstract?
The geoip gem queries a local MaxMind GeoLite2 database file that you download and maintain yourself, which means lookups are fast and offline but the database needs regular updates and provides a limited set of fields. An external API like Abstract handles updates automatically and includes richer data like VPN detection and timezone, at the cost of an outbound HTTP request per lookup.
How do I use IP geolocation to automatically set the locale in Rails?
Add a before_action :set_locale hook in ApplicationController that resolves the locale from params[:locale], then session[:locale], then falls back to the IP-derived country using a geolocation call, and finally to I18n.default_locale. Store the resolved value in the session so subsequent requests skip the geolocation lookup. The rails-i18n gem provides ready-made translation files for common locales.
How accurate is IP geolocation in a Rails application?
IP geolocation is generally accurate to the country or region level, but city-level accuracy can vary because ISPs may route traffic through infrastructure in a different city than the user's actual location. Results are also less reliable for users behind VPNs, proxies, or corporate networks. For use cases that require precise location, combine IP geolocation with browser-based Geolocation API consent where possible.


