While working on a small project that needed to return content based on the user's country, I found a convenient, free approach to get the user's country from the IP address in the request object without relying on API calls. However, this approach has its caveats, as you must regularly update your database.
The approach I will discuss involves using a database provided by MaxMind to query IP address information. While there are various types of information you can query, we will focus solely on retrieving the country ISO and city in this article. There are packages that can be used to achieve this, such as geoip-lite or fast-geoip.
We will explore two approaches: one that requires setting up an account with MaxMind to download the latest data, and another that uses a GitHub repository with a frequently updated downloadable database.
If you plan to use this service at an enterprise level, please purchase a MaxMind license to access a more accurate and up-to-date database.
Using Database from Your MaxMind Account
- Register for a MaxMind account.
- Create a license key (Optional). This is only needed for updating the database.
- Go to
My Account
and selectDownload Database
. Download the database in the format of your choice. We will use the binary (.mmdb) format in this article. Download the zip file and extract it on your server. The CSV format is ideal if you want to dump the data into a database like PostgreSQL or MySQL. You can find the guide to do that here.
Code Implementation for Country ISO
import { Reader } from "@maxmind/geoip2-node";
import { readFileSync } from "fs";
// Synchronous database opening
const dbBuffer = readFileSync("GeoLite2-Country.mmdb");
// This reader object should be reused across lookups as creation of it is expensive.
const reader = Reader.openBuffer(dbBuffer);
const ipAddr = "154.113.170.145";
const IP2Country = (ip) => {
try {
const { country } = reader.country(ip);
return country
? { countryCode: country.isoCode, country: country.names["en"] }
: null;
} catch (error) {
console.log(error); // Handle the error as needed. You can make an API call here.
return null;
}
};
console.log(IP2Country(ipAddr));
// { countryCode: "NG", country: "Nigeria" }
You can also download the database with city records, which allows you to retrieve city information. Note that the city data may not be available for some IP addresses, so you will need to handle such cases. You should consider purchasing a license to access a more accurate database.
Code Implementation for City Information
import { Reader } from "@maxmind/geoip2-node";
import { readFileSync } from "fs";
// Synchronous database opening
const dbBuffer = readFileSync("GeoLite2-City.mmdb");
// This reader object should be reused across lookups as creation of it is expensive.
const reader = Reader.openBuffer(dbBuffer);
const ipAddr = "154.113.170.145";
const IP2City = (ip) => {
try {
const { country, city, continent } = reader.city(ip);
return {
city: city?.names["en"],
country: country?.names["en"],
countryCode: country?.isoCode,
continent: continent?.names["en"],
};
} catch (error) {
console.log(error); // Handle the error as needed. You can make an API call here.
return null;
}
};
console.log(IP2City(ipAddr));
// { city: "Lagos", country: "Nigeria", countryCode: "NG", continent: "Africa" }
The city database is quite large and can be resource-intensive to load into memory, depending on your server resources. If city data is necessary for your service, I recommend downloading the CSV database and importing it into your database to query. The guide can be found here.
Using Database from Sapic IP-Location-DB GitHub Repository
This approach does not require setting up a MaxMind account, as the database files are already available in the repository and are frequently updated.
- Go to the repository and select geolite2-country-mmdb to download the database. We will be using the IPv4 binary database, but you can also download the IPv6 database and implement the function if needed.
This minimal database is resource-efficient, as the data loaded into memory is smaller.
Code Implementation for Country ISO (Using Sapic Repository)
import { readFileSync } from "fs";
import { Reader } from "maxmind";
// Synchronous database opening
const dbBuffer = readFileSync("geolite2-country-ipv4.mmdb");
// This reader object should be reused across lookups as creation of it is expensive.
const reader = new Reader(dbBuffer);
const ipAddr = "154.113.170.145";
const IP2Country = (ip) => {
try {
return { countryCode: reader.get(ip).country_code };
} catch (error) {
console.log(error); Handle the error as needed. You can make an API call here.
}
};
console.log(IP2Country(ipAddr));
// { countryCode: "NG" }
Code Implementation for City Information (Using Sapic Repository)
import { readFileSync } from "fs";
import { Reader } from "maxmind";
// Synchronous database opening
const dbBuffer = readFileSync("geolite2-city-ipv4.mmdb");
// This reader object should be reused across lookups as creation of it is expensive.
const reader = new Reader(dbBuffer);
const ipAddr = "154.113.170.145";
const IP2City = (ip) => {
try {
const { city, country_code } = reader.get(ip);
return { city, countryCode: country_code };
} catch (error) {
console.log(error); // Handle the error as needed. You can make an API call here. }
};
console.log(IP2City(ipAddr));
// { city: "Lagos", countryCode: "NG" }
Conclusion
In this article, we explored two ways to retrieve country and city data from an IP address without relying on API requests. Both methods involve using a local database that needs to be updated regularly to ensure new IP addresses are included. It is essential to automate the process of downloading the latest database and updating your local copy, as MaxMind updates its GeoLite2 database every Tuesday and Friday. You should set up a job that runs to update your database and keep in mind that the database size will grow as it is being updated. Here is a solution created by MaxMind.
Ensure you abide by MaxMind's terms of service when using the data, and consider purchasing a license for more accurate and up-to-date information.
Top comments (0)