Universal Geocoder is a universal JavaScript library for server-side and client-side geocoding applications with multiple built-in providers.
Need geocoding 🌍️ in your website or application? Don't want to be vendor-locked to a service? ✨️ Universal Geocoder ✨️ is for you!
Depending of the chosen provider, it can use geocoding, reverse geocoding or IP geolocation.
Universal Geocoder is a TypeScript fork of GeocoderJS, itself a port of the Geocoder PHP library.
This library is platform agnostic: it is available either server-side (Node) or client-side (browsers, React Native, Electron).
It aims to be compatible with a maximum of browsers (even old ones) and provides multiple ways to use it, from an old use (available in global environment, results from callbacks) to the most modern use (available as a module, async / await results).
Add the library to your project:
npm install --save universal-geocoder
⚠️ Warning: If you need to use this library in an environment not supporting the Promise API such as Internet Explorer, you must install an ES6 Promise compatible polyfill like es6-promise.
You can either use Universal Geocoder as a module (both CommonJS and ES module syntaxes are provided) or as a direct dependency.
As a module:
import UniversalGeocoder from "universal-geocoder";
const openStreetMapGeocoder = UniversalGeocoder.createGeocoder("openstreetmap");
// async / await syntax
(async () =>
console.log(await openStreetMapGeocoder.geocode("1600 Pennsylvania Ave NW, Washington, DC"))
)();
// callback syntax
openStreetMapGeocoder.geocode("1600 Pennsylvania Ave NW, Washington, DC", (result) => {
console.log(result);
});
For this example, the output will be something like this:
[
NominatimGeocoded {
coordinates: { latitude: 38.8976998, longitude: -77.03655348862276 },
bounds: {
latitudeSW: 38.8974898,
longitudeSW: -77.0368542,
latitudeNE: 38.897911,
longitudeNE: -77.0362526
},
formattedAddress: undefined,
streetNumber: '1600',
streetName: 'Pennsylvania Avenue Northwest',
subLocality: undefined,
locality: 'Washington',
postalCode: '20500',
region: 'District of Columbia',
adminLevels: [
AdminLevel {
level: 1,
name: 'District of Columbia',
code: undefined
},
AdminLevel {
level: 2,
name: 'Washington',
code: undefined
}
],
country: 'United States of America',
countryCode: 'us',
timezone: undefined,
displayName: 'White House, 1600, Pennsylvania Avenue Northwest, Washington, District of Columbia, 20500, United States of America',
osmId: 238241022,
osmType: 'way',
category: 'historic',
type: 'castle',
attribution: 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright'
},
// ... (other results)
]
If you want to use the library as a direct dependecy (for browsers only), copy dist/universal-geocoder.js
or dist/universal-geocoder.min.js
to your dependencies.
Universal Geocoder will be available in the global environment:
const openStreetMapGeocoder = UniversalGeocoder.createGeocoder("openstreetmap");
openStreetMapGeocoder.geodecode("44.915", "-93.21", (result) => {
console.log(result);
});
For a more advanced usage, see the example below:
import UniversalGeocoder, { ReverseQuery } from "universal-geocoder";
const googleGeocoder = UniversalGeocoder.createGeocoder({
provider: "googlemaps",
apiKey: "YOUR_API_KEY",
useSsl: true,
useJsonp: false,
// other specific provider options
});
(async () =>
console.log(await googleGeocoder.geocode({
text: "1600 Pennsylvania Ave, Washington, DC",
locale: "FR",
limit: 10,
// other specific provider parameters
}))
)();
const reverseQuery = ReverseQuery.create({
coordinates: {
latitude: "44.915",
longitude: "-93.21",
},
})
.withLocale("FR")
.withLimit(7);
(async () =>
console.log(await googleGeocoder.geodecode(reverseQuery))
)();
useSsl
: boolean to use the HTTPS API of the providersuseJsonp
: boolean to use JSONPapiKey
: the API key to use for the provider
text
: what is searchedip
: the IP searchedbounds
(object withlatitudeSW
,longitudeSW
,latitudeNE
andlongitudeNE
keys): the bounds to use (either bias or filter the results)locale
: the locale to use for the querylimit
: the maximum number of results to have
coordinates
(object withlatitude
,longitude
keys): the coordinates to search forlocale
: the locale to use for the querylimit
: the maximum number of results to have
The result of a query is a Geocoded
object which maps the following common information:
- Coordinates (object with
latitute
andlongitude
keys) - Bounds (object with
latitudeSW
,longitudeSW
,latitudeNE
,longitudeNE
keys) - Formatted address
- Address details: street number, street name, (sub) locality, postal code, region, administration levels, country (with its code)
- Time zone
You can either use getter methods to retrieve them or use the toObject
method to manipulate an object containing the properties.
Universal Geocoder comes with modules to integrate with various geocoding providers.
The following table summarizes the features of each:
Provider | Codename | Supports location geocoding? | Supports reverse geocoding? | Supports IP geolocation? |
---|---|---|---|---|
OpenStreetMap (Nominatim) | openstreetmap or nominatim | ✅️ yes | ✅️ yes | ❌️ no |
OpenCage | opencage | ✅️ yes | ✅️ yes | ❌️ no |
Google Maps (Geocoding API) | google or googlemaps | ✅️ yes | ✅️ yes | ❌️ no |
LocationIQ | locationiq | ✅️ yes | ✅️ yes | ❌️ no |
Mapbox | mapbox | ✅️ yes | ✅️ yes | ❌️ no |
MapQuest | mapquest | ✅️ yes | ✅️ yes | ❌️ no |
Bing | bing | ✅️ yes | ✅️ yes | ❌️ no |
Yandex | yandex | ✅️ yes | ✅️ yes | ❌️ no |
GeoPlugin | geoplugin | ❌️ no | ❌️ no | ✅️ yes |
The documentation for specific provider options, parameters and results can be found here.
A chain
provider is available: it iterates over multiple providers.
For more information, see its documentation.
Dumpers transform a Geocoded
object to another format.
GeoJSON is a format for encoding a variety of geographic data structures.
import UniversalGeocoder, { GeoJsonDumper } from "universal-geocoder";
const nominatimGeocoder = UniversalGeocoder.createGeocoder("nominatim");
(async () => {
const result = await nominatimGeocoder.geocode("1600 Pennsylvania Ave NW, Washington, DC");
console.log(result);
console.log("GeoJSON:", GeoJsonDumper.dump(result[0]));
})();
npm run build
Unit and functional tests are handled by Jasmine. To run tests from the command line, use:
npm test
If you need to record new API calls, use:
npm run test-record
You can also check if the examples are running correctly.
For the Web:
npm run serve
Then go to http://localhost:8080/example/web, choose a provider and open the console.
For Node:
npm run ts-node -- example/node/provider.ts
Q: When using Universal Geocoder client-side, how to make sure the API key is not stolen?
A: First of all, there are some providers that do not use an API key, like OpenStreetMap (Nominatim) or GeoPlugin.
If you want to use a provider with an API key, the best approach is generally to use Universal Geocoder in the server-side (Node) and to call it from the client-side. This way the API key is not exposed directly.
Some providers allow to add URL restrictions when generating a token, like Mapbox.
Even if the token is visible, it mitigates its unwanted use since the Origin
header cannot be changed in a browser environment.
However, the stolen token would be still usable in a server environment (for instance with cURL).