Nominatim vs Photon geocoder

Looking up a location given free-form address is one of the most frequent operations on geospatial data. Almost every business needs to recognize and locate customer addresses. At the same time, differences in languages, country-specific address and postcode formats, typos and ambiguous names make it very hard to do it right.

This is why one normally uses a geocoder – a specialized search engine that is designed to return the most relevant location for a given address string.

Feature comparison

Nominatim geocoder is a “de-facto” standard in the world of open source geocoding engines. It is developed and maintained by the OpenStreetMap community.

Photon is another popular open-source geocoder with the focus on search-as-you-type suggestions and typos correction. It is developed and maintained by Komoot.

Both geocoders are fine pieces of software, supporting both forward and reverse geocoding and primarily use the OpenStreetMap dataset for address lookups.

Structured searchyesno
Hardware requirementshighmedium
Typo tolerancenoyes
Filtering resultsbounding box
county code
special phrases
bounding box
OSM tag name and value
Ranging resultsnolocation bias
Data sourcesOpenStreetMap
US Tiger & Postcodes
UK Postcodes
Response formatsGeoJSON
Returned datafull, including geometrybasic
User interfaceyesno


So, which geocoder is the best, Nominatim or Photon? As usual, the answer is – it depends.

Photon excels in search-as-you-type scenarios. It tolerates typos and spelling mistakes. Photon is good for a general, free-form text geocoding. It is relatively lightweight and not very difficult to maintain – setting up your own instance takes from few hours to few days.

Nominatim on another hand has superior structured address search and filtering capabilities. It supports a number of output formats and advanced filters. Nominatim works best in scenarios when you at least roughly know what you’re looking for and where. Nominatim comes with significant complexity, hardware requirements, and maintenance overhead. It may take days and weeks to configure your own functional Nominatim instance.

In both cases, you’ll need to have expertise and time to set up your own geocoder instance. Alternatively, you can use our managed Photon and Nominatim geocoder instances. We take care of all aspects – configuration, updates, maintenance, availability, and security. We also provide consulting and custom software development. In case you’re looking for high-volume batch geocoding or cannot use 3rd party services due to security or privacy regulations, we can also set up a dedicated geocoder instance for you.

Travel time map: TOP 10 use cases for businesses and individuals

Travel time is one of the most important criteria when you choose a location. That’s why a travel time map or isochrone is often used as the main analytics tool to answer spatial questions. In this article, we would like to show you some scenarios of how travel time maps can help to make a location decision.

Travel time map use cases for businesses

While Location Intelligence becomes one of the key tools of Business Intelligence travel time maps become more and more popular in the business world. Here are a few examples of the isochrones application which could solve business tasks.

Operations on travel time maps
Union and intersection of travel time maps

Choose a new office location

Relocation is always a big step for a company. It’s important not only to satisfy the needs of the existing employees but also choose an attractive location for the new employees.

You can build reachability maps with desired time for each of your current employees and check if there is an intersection between them. Moreover, with isochrones, you can filter statistics and check how many potential workers are living in the bounded area of a new office.

Check coverage of your network

You can build isochrones for each of your selling points and check their union to see the coverage of your network. Different transportation modes, for example, “by public transport”, “driving”, or “walking”, help you to see if there are empty spots on your coverage map.

Choose the best place for a new retail shop

Not only vacant spots but also potentially profitable locations could be found with Location Intelligence tools and isochrones. For example, you can see if your target auditory can reach a new location easily. Moreover, you can filter properties by isoline and check exact numbers for the location.

Estimate a place reachability

It’s always good to rank locations by reachability. How good is the public transport connection for a place? How big reachability area by car? Better connectivity will always provide more potential and perspectives for a location. In short, travel time maps are designed to solve this task as well.

Study opportunities and potential of a location

When you have statistical data, for example, demographic data, you can bound the data by travel time maps and get statistics by isochrones. So you can study opportunities and potential clients, who can reach the location within the desired amount of time.

Travel time map use cases for individuals

Not only businesses but also individuals can benefit using isochrones. Thus if you provide the service on your website, the website becomes more valuable and attractive for your customers.

Transit isochrone
30 min isochrone for public transport

Optimize commute time by choosing the right place to live

It’s know fact, that fewer time people spend commuting, happier they are. Isochrones can help you to optimize commute time for each family member to their working or study place. If you build the travel time maps and then calculate the intersection of them, you can see locations reachable from each point of interests.

Optimize commute time by choosing the right place to work

Moreover, the inverse problem also could be solved with isochrones. If you plan to change your working place, the travel time map could show you all the possible areas where a new working place could be.

Study amenities you can reach

Would you like to see on the map only amenities you can reach within the desired time? Sure, it would be great! Filtering amenities by an isochrone provides you the answer.

Amenities filtered by the travel time map
All dentists within 30 min by public transport

Choose the best place to stay in a new city

When you plan a trip to a city you’ve never visited before it always a challenge to book accommodation in a good location. Often you need a good transport connection to multiple points of interest. For example, to the airport and conference place. Intersection on travel time maps of each of the locations will show you the perfect place for accommodation.

Book a hotel within desired travel time from seaside or ski resort

Isolines will also help you to book a hotel within walking or driving distance from seaside or ski resort. By calculating union of beach entries or ski lifts reachability maps, you can see on a map where hotels with an acceptable walking or drive time are.

Geoapify provides Isoline API to build travel time maps

Isolines API allows you to build travel time maps for different traveling modes and all over the world. Our APIs work via HTTP Get requests and return GeoJSON object as a result. Moreover, we provide Geometry API which calculates intersections and unions of isochrones. So you can quickly and with ease create your own Location Intelligence solution or extend an existing one. Register and start building isochrones for free.

Map animation with Mapbox GL

What can be more eye-catching than smooth, interactive, three-dimensional map animation? Impress your visitors by displaying your map data in stunning 3D!

Previously we have compared OpenLayers and Leaflet map libraries. Both are great choices if you want to add interactive map to your website. They are free, battle-tested, extensible and supported by active communities.

But what if you need a very fast, animated, eye-catching 3D map? Both Leaflet API and OpenMapLayersAPI do not support 3D and free-form map rotation. In this case Mapbox GL map library can be a great option.

Mapbox GL JS is one of the most advanced JavaScript map rendering libraries when it comes to smooth interactive animation. Mapbox GL API is slightly harder to use and not compatible with existing Leaflet plugins and examples. But it is using hardware-accelerated WebGL technology to dynamically draw data with the speed and smoothness of a video game.

In this article I’ll show you how to animate and implement 3D map rotation around a selected point. The end result should look like this:

Map rotation animation in 3D with Mapbox GL

If you short on time and just looking for the complete HTML code, you can find it at the bottom of the page.

Setting up our 3D map

As first step, we need to add imports for Mapbox GL library and its CSS style sheet into the HEAD of our page

<link rel="stylesheet" href="" />
<script src=""></script>

Once imported, we can define a <div> element which will host map visualization and add Javascript code which will initialize Mapbox GL to render our map in 3D with specified initial location, zoom, pitch and bearing. Please do not forget to put your real API key instead of “YOUR_API_KEY” placeholder in the map tiles URL.

<div id='map'></div>
var map = new mapboxgl.Map({
    container: 'map',
    style: {
        "version": 8,
        "sources": {
            "basemap": {
                "type": "raster",
                // map tile source 
                "tiles": [
                "tileSize": 256
        "layers": [{
            "id": "basemap",
            "type": "raster",
            "source": "basemap",
            "minzoom": 0,
            "maxzoom": 22
    center: [-73.991462, 40.724637], // starting position
    zoom: 12, // starting zoom
    pitch: 60, // starting pitch in degrees
    bearing: 0, // starting bearing in degree

This should give us basic interactive 3D map. You should be able to move the map to a different locations, zoom in and out, and change view angle.

Interactive 3D map view of Manhattan, NY
Interactive 3D map view of Manhattan, NY

Adding map rotation animation

As next step, let’s add dynamic map animation, which will change view angle to create effect of flying around the map center. Please add the following code into our <script> block and refresh the page:

function rotateCamera(timestamp) {
    // rotate at approximately ~10 degrees per second
    map.rotateTo((timestamp / 100) % 360, {duration: 0});
    // request the next frame of the animation

map.on('load', function () {
    // start the animation

Final steps

As the last step, let’s add basic map navigation controls and basemap attribution.

// map navigation controls
map.addControl(new mapboxgl.NavigationControl());

// attribution
map.addControl(new mapboxgl.AttributionControl({
	compact: false,
	customAttribution: 'Powered by <a href="">Geoapify</a> | © <a href="">OpenStreetMap</a> contributors'
Complete map with controls and attribution
Complete map with controls and attribution

Complete HTML code

Final version of the HTML page could look like this. Please feel free to copy the code, insert API key and open it in your browser to see how it works.

    <meta charset='utf-8' />
    <title>Mapbox GL example: rotate map animation in 3D</title>
    <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
    <link rel="stylesheet" href="" />
    <script src=""></script>
        body { margin:0; padding:0; }
        #map { position:absolute; top:0; bottom:0; width:100%; }

<div id='map'></div>
var map = new mapboxgl.Map({
    container: 'map',
    style: {
        "version": 8,
        "sources": {
            "basemap": {
                "type": "raster",
                // map tile source 
                "tiles": [
                "tileSize": 256
        "layers": [{
            "id": "basemap",
            "type": "raster",
            "source": "basemap",
            "minzoom": 0,
            "maxzoom": 22
    center: [-73.991462, 40.724637], // starting position
    zoom: 12, // starting zoom
    pitch: 60, // starting pitch in degrees
    bearing: 0, // starting bearing in degree

function rotateCamera(timestamp) {
    // rotate at approximately ~10 degrees per second
    map.rotateTo((timestamp / 100) % 360, {duration: 0});
    // request the next frame of the animation

map.on('load', function () {
    // start the animation

// map navigation controls
map.addControl(new mapboxgl.NavigationControl());

// attribution
map.addControl(new mapboxgl.AttributionControl({
	compact: false,
	customAttribution: 'Powered by <a href="">Geoapify</a> | © <a href="">OpenStreetMap</a> contributors'



Mapbox GL generally requires more JavaScript code to be written than Leaflet and can be more complicated to maintain.

So, you may ask when to use Leaflet and when to use Mapbox GL?

The answer is simple – if you don’t need 3D and extremely fast animation then Leaflet would be the best choice. It has biggest community, best documentation, extensive set of plugins and works well in any situation. And if you really need advanced 3D maps with animations and top rendering speed on modern devices – then Mapbox GL is your friend.

Create a map with Location Intelligence components

Does it make sense to create a custom map for your website? Sure, a custom map brings a lot of benefits and advantages to your website. For instance, with your own map you are able to show the important locations to customers, highlight areas you want to pay attention to, and visualize data which could be potentially very interesting for both sites.

Geoapify helps you to create a map from the beginning and add Location Intelligence components into it. Read how to add a map to your website.

However, location visualizations are not only what people look for on a map. It’s also important to make the map interactive and “alive”. So the users can interact and “play” with it and make location decisions.

Make your custom map “alive”

But what does make a custom map “alive”? How to make the map interactive? The answer is simple: add components to your custom map, where a user can enter his data and analyze outcome.

This could be an input to search a location, popups opening on a click and giving some details or location analytics components like routing or isochrones.

Turn your map into Location Intelligence application

Geoapify offers APIs and map components which help to turn your map not just into the interactive map but into a Location Intelligence application of the full value.

Geocoding API to create a location input field

It’s always great to have a location input on your map. However, it’s forgotten by many map developers. The service which allows you to look for locations address details by search string is called Geocoding.

As a result, with Geoapify Geocoding API you are able to specify the search and retrieve accurate results. As well as implement autocomplete fields.

Location autocomplete input

Check our Geoacoding API in the Playground.

Reverce Geocoding API to get a location address by its coordinates

Another useful geospatial tool is Reverse Geocoding API. It returns a place address by its coordinates. With Reverse Geocoding API you are able to answer the question “What is located here?”, when a user clicks on the map.

Check our Reverse Geoacoding API in the Playground.

Routing API to build a path

Often people search locations on a map which are close to their route. Although route building is so popular, it’s present only on very several maps. By using Routing API together with Geocoding API, you can create a convenient routing tool for your map on your website.

Routing for your web site

Check our Routing API in the Playground.

Isolines API to analyse travel times

Can you show your customers what can the get from their living or working place? Sure! With Isolines API! By using the API you will be able to highlight areas on a map reachable within a given time. Together with driving and walking modes, our Isoline APIs work with transit and bicycle modes.

Isochrone for travel time analytics

Check our Isoline API in the Playground.

Places API to show amenities near by

Last but not least are amenities and points of interest. Show your customers places they interested in. Restaurants, fitness studios, schools, and other places.

Check our Places API in the Playground.

Use Geoapify APIs to create a map for your website

Read more about our APIs here.

Location autocomplete with Angular

Geoapify provides an API which allows searching a location by the query string. In this article, we provide you an example of how to create a location autocomplete field by using Geoapify Geocoding API.

In our example, we use Angular platform together with Angular Material framework.

Geoapify Geocoding API Playground contains a working example of the location autocomplete described in this article.


  • Angular Material installed. Read about installation here.

Step 1. Create a new component for a location autocomplete

Create a new component with Angular Cli command:

ng generate component Autocomplete

Step 2. Required imports

To make the component from this tutorial work, it’s required to import the following modules into your module:

  declarations: [..., AutocompleteComponent],
  imports: [
  exports: [...]

Step 3. HTML template

We use the following components:

  • mat-form-input
  • mat-input
  • mat-autocomplete
  • mat-tooltip
  • formControl from ReactiveFormsModule.

Add the following code into your component html template:

<mat-form-field floatLabel="never">
  <input matInput type="text" [matAutocomplete]="auto" 
    [formControl]="inputFieldFormControl" placeholder="Enter location here" />

  <mat-autocomplete #auto="matAutocomplete" autoActiveFirstOption>
    <mat-option *ngFor="let option of searchOptions | async" [value]="option.shortAddress" 
      (onSelectionChange)="optionSelectionChange(option, $event)"
      [matTooltip]="option.fullAddress" matTooltipShowDelay="1000">
      <span class="mat-body">{{ option.shortAddress }}</span>

Here is an idea of how the location autocomplete will work:

  • The string value will be stored in the “inputFieldFormControl” reactive form field.
  • The “inputFieldFormControl” field fires an event when its value was changed.
  • When an event fired we send an HTTP Get request to Geocoding API to retrieve place suggestions and store them in “searchOptions”.
  • mat-autocomplete loads options from the “searchOptions” asynchronously.

Step 4. AutocompleteComponent class

Here is the code of the AutocompleteComponent class:

import { Component, Output, EventEmitter, OnDestroy } from '@angular/core';
import { MatOptionSelectionChange } from '@angular/material';
import { Subject, Subscription } from 'rxjs';
import { FormControl } from '@angular/forms';
import { HttpClient } from '@angular/common/http';

  selector: 'app-autocomplete',
  templateUrl: './autocomplete.component.html',
  styleUrls: ['./autocomplete.component.scss']
export class AutocompleteComponent implements OnDestroy {
  locationChange: EventEmitter<PlaceSuggestion> = new EventEmitter<PlaceSuggestion>();

  searchOptions: Subject<PlaceSuggestion[]> = new Subject<PlaceSuggestion[]>();
  inputFieldFormControl: FormControl = new FormControl();

  private valueChangesSub: Subscription;
  private choosenOption: PlaceSuggestion;

  private userInputTimeout: number;
  private requestSub: Subscription;

  constructor(private http: HttpClient) {
    this.valueChangesSub = this.inputFieldFormControl.valueChanges.subscribe((value) => {
      if (this.userInputTimeout) {

      if (this.choosenOption && this.choosenOption.shortAddress === value) {;

      if (!value || value.length < 3) {
        // do not need suggestions until for less than 3 letters;

      this.userInputTimeout = window.setTimeout(() => {
      }, 300);

  ngOnDestroy() {

  private generateSuggestions(text: string) {
    const url = `${text}&limit=5&api_key=${YOUR_API_KEY}`;

    if (this.requestSub) {

    this.requestSub = this.http.get(url).subscribe((data: GeoJSON.FeatureCollection) => {
      const placeSuggestions = => {
        const properties: GeocodingFeatureProperties = ( as GeocodingFeatureProperties);

        return {
          shortAddress: this.generateShortAddress(properties),
          fullAddress: this.generateFullAddress(properties),
          data: properties
      }); ? placeSuggestions : null);
    }, err => {

  private generateShortAddress(properties: GeocodingFeatureProperties): string {
    let shortAddress =;

    if (!shortAddress && properties.street && properties.housenumber) {
      // name is not set for buildings
      shortAddress = `${properties.street} ${properties.housenumber}`;

    shortAddress += (properties.postcode && ? `, ${properties.postcode}-${}`: '';
    shortAddress += (!properties.postcode && &&  !== ? `, ${}`: '';
    shortAddress += ( && !== ? `, ${}` : '';

    return shortAddress;

  private generateFullAddress(properties: GeocodingFeatureProperties): string {
    let fullAddress =;
    fullAddress += properties.street ? `, ${properties.street}` : '';
    fullAddress += properties.housenumber ? ` ${properties.housenumber}` : '';
    fullAddress += (properties.postcode && ? `, ${properties.postcode}-${}`: '';
    fullAddress += (!properties.postcode && &&  !== ? `, ${}`: '';
    fullAddress += properties.state ? `, ${properties.state}`: '';
    fullAddress += ( && !== ? `, ${}` : '';
    return fullAddress;

  public optionSelectionChange(option: PlaceSuggestion, event: MatOptionSelectionChange) {
    if (event.isUserInput) {
      this.choosenOption = option;

export interface PlaceSuggestion {
  shortAddress: string;
  fullAddress: string;
  data: GeocodingFeatureProperties;

interface GeocodingFeatureProperties {
  name: string;
  country: string;
  state: string;
  postcode: string;
  city: string;
  street: string;
  housenumber: string;


As described above, the field holds the value of the search string, which is observed by this.inputFieldFormControl.valueChanges.subscribe().

To keep the code clean we save the created subscription in the variable valueChangesSub and unsubscribe on destroy.


To avoid too many unnecessary requests and decrease the application load, we perform HTTP request only when a user stops to type.

This implemented by using userInputTimeout, which sets every time when the user enters a new value.


Contain the values returned by Geocoding API and displayed by autocomplete control.

When we set, the autocomplete control is hidden.

PlaceSuggestion & GeocodingFeatureProperties

We use the interfaces to simplify work with JSON object returned by the Geocoding API. We export PlaceSuggestion to be able to use the interface in other components, services, and modules.


Is an Output() of the Autocomplete component. We this.locationChange.emit(option) when a new place suggestion was selected.

generateShortAddress() & generateFullAddress()

As Geocoding API returns value with address components, but not a formatted address, we need to generate an address string of required format. generateShortAddress() & generateFullAddress() are examples of how an address string could be generated.

Step 5. Add the Location Autocomplete component into your code

The new component could be added into your code in the following way:

<app-autocomplete (locationChange)="autocompleteChanged($event)"></app-autocomplete>

When a new value was chosen in the location autocomplete, the event is fired:

autocompleteChanged(value: PlaceSuggestion) {}

How to call HTTP Get request

All Geoapify APIs work via HTTP Get requests. In this article, we would like to highlight some examples, how to implement HTTP request in your application.

JavaScript: Get request with XMLHttpRequest object

Firstly, one HTTP request example with the XMLHttpRequest object. The XMLHttpRequest object is classical and proved by time way to build HTTP request in JavaScript.

Do not be confused by word “XML” in the name. XMLHttpRequest is very flexible in nature and allows to operate with any data type. Of cause, the method perfectly works with JSON objects as well.

For example, the implementation could look like:

var xmlHttp = new XMLHttpRequest();
xmlHttp.responseType = 'json';
var url = "";
xmlHttp.onreadystatechange = () => {
    if (xmlHttp.readyState === 4) {
        if (xmlHttp.status === 200) {
            // check xmlHttp.responseText here;
        } else {
};"GET", url, true); // true for asynchronous 

JavaScript: fetch() to build HTTP request

Another we-known way to build an HTTP request in JavaScript application is using fetch(). Fetch() provides similar functionality as XMLHttpRequest, but instead of callbacks and a bit complicated API, fetch() returns a promise. Moreover, you can define URI parameters separately as an object. So fetch() allows making your code cleaner and smaller.

For instance, fetch() could look that way in your code:

var url = new URL('');

var params = [['lat', '47.68388118858141'], ['lon', '8.614278188654232'], ['mode', 'drive'], ['type', 'time'], ['range', '2700'], ['api_key', 'YOUR_API_KEY']]; = new URLSearchParams(params);

fetch(url).then(response => response.json()).then(data => console.log(data)).catch(err => console.log(err));

Angular: HttpClient

Angular brings new standards into our code and life. The common way to implement HTTP request in Angular is by using HTTPClient.

You just add HttpClient to a class constructor and call get(). However, don’t forget to import HttpClientModule in your module file. The data returned is already in JSON format, you do not need to convert it separately.

// import BrowserModule and HttpClientModule in a module file
constructor(private httpClient: HttpClient, ...) {


getData() {
  const url = "";

  this.httpClient.get(url).subscribe(data => {
    // check for returned data
  }, err => {
    // check for error

HTTP Request in Terminal

Sometimes it’s useful to call HTTP requests from terminal to check if the functionality works independently from a platform or framework. You can do it with curl, for example:

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET ""

Geoapify APIs to create a map

Our APIs help to create an interactive map with Location Analytics features. For example, your mapping could contain a search field, routing or travel time maps. As our APIs work through HTTP Get requests, they are independent of the framework you use. Register and start using our APIs now, read more about APIs or try them out in Playground.