Fast location lookup from IP address
npm install ip-location-apiip-location-api make a fast lookup by using in-memory database.
javascript
import { lookup } from 'ip-location-api'
// or CJS format
// const { lookup } = require('ip-location-api')
// for module bandle (eg., webpack, next.js, etc.)
// import { lookup } from 'ip-location-api/pack'
var ip = "207.97.227.239"
var location = lookup(ip)
// If you use Asynchronouns version which is configured with smallMemory=true,
// var location = await lookup(ip)
console.log(location)
{
country: 'FR',
region1: 'NOR',
region1_name: 'Normandy',
region2: '27',
region2_name: 'Eure',
city: 'Heudicourt',
// metro: Defined only in US (Aug.2024)
timezone: 'Europe/Paris',
eu: 1,
latitude: 49.3335,
longitude: 1.6566,
area: 5,
postcode: 27860,
country_name: 'France',
country_native: 'France',
phone: [ 33 ],
continent: 'EU',
capital: 'Paris',
currency: [ 'EUR' ],
languages: [ 'fr' ],
continent_name: 'Europe'
}
`
Benchmark
I make a benchmark for making comparison with intel 12700 (2.1GHz), SSD, nodejs v20.
You can change the memory usage or lookup time, by customizing location information.
| benchmark | type | in-memory db | startup | lookup ipv4 | lookup ipv6 |
| ---- | ---- | ---- | ---- | ---- | ---- |
| ip-location-api
(default) | country | 6.9 MB | 3 ms | 0.362 μs/ip | 0.708 μs/ip |
| ip-location-api
(async) | country | 2.9 MB | 2 ms | 243 μs/ip | 255 μs/ip |
| ip-location-api | city | 62.9 MB | 14 ms | 0.751 μs/ip | 1.064 μs/ip |
| ip-location-api
(async) | city | 15.6 MB | 5 ms | 267 μs/ip | 271 μs/ip |
| geoip-lite | city | 136 MB | 54 ms | 1.616 μs/ip | 3.890 μs/ip |
| fast-geoip
(async) | city | 0MB | 4 ms | 1714 μs/ip | cannot lookup |
Installation
`bash
$ npm i ip-location-api
`
API
ip-location-api has two modes which are synchronous and asynchronous.
Synchronouns one load all data in-memory at startup time, thus it makes fast lookup.
Asynchronouns one load smaller data in-memory at startup time, and the other data is loaded from the hard drive for each lookup.
| type | memory usage | startup | lookup |
| ---- | ---- | ---- | ---- |
| Synchronouns | Large | Slow | Fast |
| Asynchronouns | Small | Fast | Slow |
If you have a enough memory, I recommend to use synchronouns one because lookup is over 300 times faster than asynchronouns one.
Field description
Note that as far as possible, the same field names as in geoip-lite are used, but some different field names are used.
| ip-location-api | geoip-lite | database |description |
| ---- | ---- | ---- | ---- |
| country | country | MaxMind | "2 letter" country code defined at ISO-3166-1 alpha-2 |
| region1 | region | MaxMind | region code which is short code for region1_name ISO 3166-2 |
| region1_name | ❌️ | MaxMind | first sub division name (multi language) |
| region2 | ❌️ | MaxMind | region code which is short code for region2_name ISO 3166-2 |
| region2_name | ❌️ | MaxMind | second sub division name (multi language) |
| city | city |MaxMind | city name (multi language) |
| metro | metro |MaxMind | Geolocation target code from Google |
| eu | eu | MaxMind | true: the member state of the European Union, undefined: for the other countries. This needs "country" field. |
| timezone | timezone | MaxMind | time zone associated with location |
| latitude | ll[0] | MaxMind | approximate WGS84 latitude |
| longitude | ll[1] | MaxMind | approximate WGS84 longitude |
| area | area | MaxMind | The radius in kilometers around the specified location where the IP address is likely to be. maxmind blog |
| postcode | ❌️ | MaxMind | region-specific postal code near the IP address |
| ❌️ | range | MaxMind | We removes range information for optimization |
| country_name | ❌️ | Countries| country name|
| country_native | ❌️ | Countries| country name in native language|
| continent | ❌️ | Countries| continent short code|
| continent_name | ❌️ | Countries| continent name|
| capital | ❌️ | Countries | capital name |
| phone | ❌️ | Countries| international country calling codes |
| currency | ❌️ | Countries | list of commonly used currencies |
| languages | ❌️ | Countries | list of commonly used languages |
Setup the configuration
You can configure the api by 3 way.
- CLI parameters: ILA_FIELDS=latitude,longitude
- Environment variables: ILA_FIELDS=latitude,longitude
- Javascript: await reload({fields: 'latitude,longitude'}) .
The name of CLI prameter and environment variables are same.
Conf key in reload(conf) is named with "LOWER CAMEL", CLI or ENV parameter is named with "SNAKE" with adding "ILA_" (come from Ip-Location-Api).
| reload(conf) | CLI or ENV | default | description |
| ---- | ---- | ---- | ---- |
| fields | ILA_FIELDS | country | You can change the fields to be retrived from MaxMind. When you set "all", all fields are displayed. |
| addCountryInfo | ILA_ADD_COUNTRY_INFO | false | "true" make to add the country information from Countries. This needs "country" field. |
| dataDir | ILA_DATA_DIR | ../data | Directory for database file |
| tmpDataDir | ILA_TMP_DATA_DIR | ../tmp | Directory for temporary file |
| apiDir | ILA_API_DIR | .. | Directory for ip-location-api |
| smallMemory | ILA_SMALL_MEMORY | false | false: synchronouns, true: asynchronouns |
| smallMemoryFileSize | ILA_SMALL_MEMORY_FILE_SIZE | 4096 | Max file size for asynchronouns data (no change is recommended) |
| licenseKey | ILA_LICENSE_KEY | redist | By setting MaxMind License key, you can download latest version of database from MaxMind server. By setting to "redist", you can download the database from node-geolite2-redist repository which re-distribute the GeoLite2 database. |
| ipLocationDb | ILA_IP_LOCATION_DB | | When you need only "country" field, you can use ip-location-db data |
| downloadType | ILA_DOWNLOAD_TYPE | reuse | By setting to "false", "tmpDataDir" directory is deleted every update. "reuse" dose not delete "tmpDataDir" and re-use "tmpDataDir"'s database if the database file dose not update. |
| autoUpdate | ILA_AUTO_UPDATE | default | By setting to "false", it dose not update automatically. "default" updates twice weekly. You can set CRON PATTERN FORMAT which is provided by cron with UTC timezone (For example, ILA_AUTO_UPDATE="0 1 *" for daily update). |
| multiDbDir | ILA_MULTI_DB_DIR | false | If you use multiple "dataDir", please make this value to "true" |
| series | ILA_SERIES | GeoLite2 | By setting to "GeoIP2", you can use premium database "GeoIP2" |
| language | ILA_LANGUAGE | en | You can choose "de", "en", "es", "fr", "ja", "pt-BR", "ru", "zh-CN". By changing, the language of "region1_name", "region2_name", "city" fields are changed |
| silent | ILA_SILENT | false | true: deactivate unnecessary console.log |
| skipInitialReload | ILA_SKIP_INITIAL_RELOAD | false | true: Skips the initial database setup, reducing startup time when you run reload separately. This also reduces build-time and memory usage in build environments. |
Update database
`bash
npm run updatedb
`
or
`javascript
import { updateDb } from 'ip-location-api'
await updateDb(setting)
`
There are three database update way.
- ILA_LICENSE_KEY=redist
- ILA_LICENSE_KEY=YOUR_GEOLITE2_LICENSE_KEY
- ILA_IP_LOCATION_DB=YOUR_CHOOSEN_DATABSE
When you set "ILA_LICENSE_KEY=redist" which is the dafault setting, it downloads GeoLite2 database from the redistribution repository node-geolite2-redist.
When you set "ILA_LICENSE_KEY=YOUR_GEOLITE2_LICENSE_KEY", it downloads GeoLite2 dastabase from the MaxMind provided server.
YOUR_GEOLITE2_LICENSE_KEY should be replaced by a valid GeoLite2 license key. Please follow instructions provided by MaxMind to obtain a license key.
When you set "ILA_IP_LOCATION_DB=YOUR_CHOOSEN_DATABSE", it downloads from the ip-location-db (country type only).
You can "YOUR_CHOOSEN_DATABSE" from ip-location-db with country type. For example, "geolite2-geo-whois-asn" is wider IP range country database which is equivalent to GeoLite2 database result for GeoLite2 country covered IP range and geo-whois-asn-country for the other IP range.
The other example, "geo-whois-asn" is CC0 licensed database, if you are unable to apply the GeoLite2 License.
It takes a few minutes to create the database.
Therefore, if you are releasing to production without a database, it is recommended that you create the database first, using commands before executing the release.
After v2.0, the database is created automatically at initial startup, and updated automatically by setting ILA_AUTO_UPDATE which updates twice weekly with default setting.
How to use with an example
When you need only geographic coordinates, please set "ILA_FIELDS=latitude,longitude".
You need to create a database for each configuration.
After v2.0.0, the database is created at initial running (which takes some seconds), and auto update with ILA_AUTO_UPDATE which update twice weekly with default setting.
The database is created by following CLI
`bash
$ npm run updatedb ILA_FIELDS=latitude,longitude
`
or
`bash
$ ILA_FIELDS=latitude,longitude # set environment variable
$ npm run updatedb
`
or you can create database with 'create.js' which includes the following.
`javascript
await updateDb({fields:['latitude', 'longitude']})
`
The CLI command for using app.js which uses ip-location-api is necessary to start with following CLI parameter
`bash
$ node app.js ILA_FIELDS=latitude,longitude
`
or environment variable
`bash
$ ILA_FIELDS=latitude,longitude # set environment variable
$ node app.js
`
or you can write down configuration in reload function of app.js as
`javascript
await reload({fields:['latitude', 'longitude']})
// or await reload({fields:'latitude,longitude'})
`
If you need all the data in above field table, setting "ILA_FIELDS=all" and "ILA_ADD_COUNTRY_INFO=true" is the one.
| benchmark | in-memory db | startup | lookup ipv4 | lookup ipv6 |
| ---- | ---- | ---- | ---- | ---- |
| longitude,latitude | 46.5 MB | 10 ms | 0.428 μs/ip | 0.776 μs/ip |
| all | 76.4 MB | 18 ms | 1.054 μs/ip | 1.348 μs/ip |
For module bundler (webpack, vite, next.js, etc)
Some module bundlers cannot work with original database system.
If module bundlers could not work with ip-location-api, please try to import module as following.
It works almost same as original module.
`js
import { lookup } from 'ip-location-api/pack'
`
It would be better to set directories for database files which have write permission.
Without write permission directories, you cannot use this module.
`bash
ILA_DATA_DIR=/your_database_directory
ILA_TMP_DATA_DIR=/your_tmporary_directory_for_database
``