Batch Geocoding API

When you need to transform a large number of addresses into geographic coordinates programmatically, you can use a Batch Geocoding API.

Batch Geocoding API is similar to our standard geocoding service, with one big difference. Rather than sending multiple requests, you geocode a list of addresses in one request.



Authenfication and API key

You need an API key to make requests using Geoapify. If you are new to our APIs, the Getting Started page will walk you through getting registered and generating an API key.

Forward Batch API Specification

To batch geocode addresses, you will need to create a batch job that processes the addresses. The results will be available when the process is complete. Once the job is complete you can get your results in either JSON or CSV format.

Creating batch job

To create a new Batch Geocoding API job, send an HTTP POST request. The address should be passed as a JSON array in the body of the request.

Request URL

POST https://api.geoapify.com/v1/batch/geocode/search?&apiKey=YOUR_API_KEY&OPTIONAL_REQUEST_PARAMS

Request Body

["ADDRESS_1", "ADDRESS_2", ... ]

Returned data example

{ 
  "id": "65d9596895e5467f89584308b09bcf2b", 
  "status": "pending", 
  "url": "https://api.geoapify.com/v1/batch/geocode/search?id=65d9596895e5467f89584308b09bcf2b&apiKey=YOUR_API_KEY"
}

The API accepts up to 1000 addresses in one batch.

Optional request params

Name Description Example
type Location type: 'country', 'state', 'city', 'postcode', 'street', 'amenity'. type=amenity
lang Result language. 2-character ISO 639-1 language codes are supported. lang=fr
filter Filter places by country, boundary, circle. See the Location Filters in Geocoding API, for more details. filter=rect:-122.569140,37.936672,-122.5324795,37.9588474
bias Prefer places by country, boundary, circle, location. See the Location Bias in Geocoding API, for more details. bias=proximity:-122.52985959,37.95335060

Getting results

The result of the previous call contains the job ID and result URL. You can use the URL to get results or generate one with the ID you received.

Request URL

GET https://api.geoapify.com/v1/batch/geocode/search?id=JOB_ID&apiKey=YOUR_API_KEY&format=csv

Pending Job

{
    "id": "65d9596895e5467f89584308b09bcf2b",
    "status": "pending"
}

JSON result example

[
    {
        "query": {
            "text": "668 Cedar St, San Carlos, CA 94070, United States of America",
            "parsed": {
                "housenumber": "668",
                "street": "cedar st",
                "postcode": "94070",
                "city": "san carlos",
                "state": "ca",
                "country": "united states of america",
                "expected_type": "building"
            }
        },
        "datasource": {
            "sourcename": "openstreetmap",
            "attribution": "© OpenStreetMap contributors",
            "license": "Open Database License",
            "url": "https://www.openstreetmap.org/copyright"
        },
        "housenumber": "668",
        "street": "Cedar Street",
        "suburb": "Devonshire",
        "city": "San Carlos",
        "county": "San Mateo County",
        "state": "California",
        "postcode": "94070",
        "country": "United States of America",
        "country_code": "us",
        "lon": -122.26380104761905,
        "lat": 37.502683380952384,
        "formatted": "668 Cedar Street, San Carlos, CA 94070, United States of America",
        "address_line1": "668 Cedar Street",
        "address_line2": "San Carlos, CA 94070, United States of America",
        "state_code": "CA",
        "result_type": "building",
        "rank": {
            "importance": 1.021,
            "popularity": 4.377368426402045,
            "confidence": 1,
            "confidence_city_level": 1,
            "confidence_street_level": 1,
            "match_type": "full_match"
        },
        "place_id": "51290bca1de2905ec05973b7d4ed57c04240f00102f901f48dac0f00000000c00203"
    }
  ...
]

CSV result example

"query.text","query.parsed.housenumber","query.parsed.street","query.parsed.postcode","query.parsed.city","query.parsed.state","query.parsed.country","query.parsed.expected_type","datasource.sourcename","datasource.attribution","datasource.license","datasource.url","housenumber","street","suburb","city","county","state","postcode","country","country_code","lon","lat","formatted","address_line1","address_line2","state_code","result_type","rank.importance","rank.popularity","rank.confidence","rank.confidence_city_level","rank.confidence_street_level","rank.match_type","place_id","category","name"
"668 Cedar St, San Carlos, CA 94070, United States of America","668","cedar st","94070","san carlos","ca","united states of america","building","openstreetmap","© OpenStreetMap contributors","Open Database License","https://www.openstreetmap.org/copyright","668","Cedar Street","Devonshire","San Carlos","San Mateo County","California","94070","United States of America","us","-122.26380104761905","37.502683380952384","668 Cedar Street, San Carlos, CA 94070, United States of America","668 Cedar Street","San Carlos, CA 94070, United States of America","CA","building","1.021","4.377368426402045","1","1","1","full_match","51290bca1de2905ec05973b7d4ed57c04240f00102f901f48dac0f00000000c00203","",""
...

Reverse Batch API specification

Similar to forward batch geocoding, to generate the reverse batch geocoding job, you have to submit a list of latitude/longitude coordinates and query the results after some time. The output format is configurable - JSON or CSV.

Creating batch job

To create a new Reverse Batch Geocoding API job, send an HTTP POST request. The address should be passed as a JSON array in the body of the request.

Request URL

POST https://api.geoapify.com/v1/batch/geocode/reverse?&apiKey=YOUR_API_KEY&OPTIONAL_REQUEST_PARAMS

Request Body

You need to send an array of lat/long pairs. The lat/long pair can be represented as an array of [longitude, latitude] or {lon: longitude, lat: latitude} objects:

[[11.021385, 48.283781], ...]

or

[{"lon": 11.021385, "lat": 48.283781}, ... ]

Returned data example

{
    "id": "dc42f860d22443f886a0f264ed325339",
    "status": "pending",
    "url": "https://api.geoapify.com/v1/batch/geocode/reverse?id=dc42f860d22443f886a0f264ed325339&apiKey=YOUR_API_KEY"
}

Optional request params

Name Description Example
type Location type: 'country', 'state', 'city', 'postcode', 'street', 'amenity'. type=postcode
lang Result language. 2-character ISO 639-1 language codes are supported. lang=fr

Getting reverse geocoding results

The previous call will return the job ID and result URL. You can use this URL to get your result or generate one with the ID you received.

Request URL

GET https://api.geoapify.com/v1/batch/geocode/reverse?id=JOB_ID&apiKey=YOUR_API_KEY&format=csv

Just add the format parameter to the request URL and get JSON or CSV in return.

Pending Job

{
    "id": "dc42f860d22443f886a0f264ed325339",
    "status": "pending"
}

JSON result example

[
    {
        "query": {
            "lon": 13.484292034147416,
            "lat": 52.54292915610742
        },
        "housenumber": "31-32",
        "street": "Konrad-Wolf-Straße",
        "distance": 96.88888772185463,
        "country": "Germany",
        "datasource": {
            "sourcename": "openstreetmap",
            "attribution": "© OpenStreetMap contributors",
            "license": "Open Database License",
            "url": "https://www.openstreetmap.org/copyright"
        },
        "country_code": "de",
        "postcode": "13055",
        "state": "Berlin",
        "district": "Berlin",
        "city": "Berlin",
        "suburb": "Alt-Hohenschönhausen",
        "lon": 13.484376,
        "lat": 52.543799,
        "result_type": "building",
        "name": "Friedhof der St. Hedwig und St. Pius Gemeinde",
        "formatted": "Friedhof der St. Hedwig und St. Pius Gemeinde, Konrad-Wolf-Straße 31-32, 13055 Berlin, Germany",
        "address_line1": "Friedhof der St. Hedwig und St. Pius Gemeinde",
        "address_line2": "Konrad-Wolf-Straße 31-32, 13055 Berlin, Germany",
        "state_code": "BE",
        "rank": {
            "popularity": 7.2715036342853825
        },
        "place_id": "5141ef8d2100f82a40597b4ca4349b454a40f00102f901528d99020000000092032d4672696564686f66206465722053742e2048656477696720756e642053742e20506975732047656d65696e6465"
    },
    ...
]

CSV result example

"query.lon","query.lat","housenumber","street","distance","country","datasource.sourcename","datasource.attribution","datasource.license","datasource.url","country_code","postcode","state","district","city","suburb","lon","lat","result_type","name","formatted","address_line1","address_line2","state_code","rank.popularity","place_id","county","category"
"13.484292034147416","52.54292915610742","31-32","Konrad-Wolf-Straße","96.88888772185463","Germany","openstreetmap","© OpenStreetMap contributors","Open Database License","https://www.openstreetmap.org/copyright","de","13055","Berlin","Berlin","Berlin","Alt-Hohenschönhausen","13.484376","52.543799","building","Friedhof der St. Hedwig und St. Pius Gemeinde","Friedhof der St. Hedwig und St. Pius Gemeinde, Konrad-Wolf-Straße 31-32, 13055 Berlin, Germany","Friedhof der St. Hedwig und St. Pius Gemeinde","Konrad-Wolf-Straße 31-32, 13055 Berlin, Germany","BE","7.2715036342853825","5141ef8d2100f82a40597b4ca4349b454a40f00102f901528d99020000000092032d4672696564686f66206465722053742e2048656477696720756e642053742e20506975732047656d65696e6465","",""
...

Code samples

As the API processes address list asynchronously, you will need to implement two steps:

  • Call an HTTP POST request on https://api.geoapify.com/v1/batch/geocode/search
  • Continuously call an HTTP GET on https://api.geoapify.com/v1/batch/geocode/search?id=JOB_ID until the job is completed.

Below are some code samples to help you get started.

Geocode a list of addresses

This is a JavaScript example that uses fetch() to make HTTP requests. If you want to implement the functionality with NodeJS, you can use the package called node-fetch.

List of addresses

For example, we’re working on a list of addresses in France to geocode:

const addresses = [
    "53 Rue de Seine, 75006 Paris, France",
    "96 Rue Saint-martin, 75004 Paris, France",
    "5 Rue Des Deux Boules, 75001 Paris, France",
    "9 Quai Saint-michel, 75005 Paris, France",
    "1 Rue Ernest Cresson, 75014 Paris, France",
    "16 Rue de Gergovie, 75014 Paris, France",
    "21 Rue Jules Michelet, 92170 Vanves, France",
    "72 Rue Sadi Carnot, 92170 Vanves, France",
    "16 Rue Antoine Fratacci, 92170 Vanves, France",
    "2 Rue Vieille Forge, 92170 Vanves, France"
];

HTTP POST to submit the addresses

Send the addresses to the batch geocode address and pick up an id to retrieve the locations:

const url = "https://api.geoapify.com/v1/batch/geocode/search?apiKey=YOUR_API_KEY";

fetch(url, {
    method: 'post',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(addresses)
  })
  .then(getBodyAndStatus)
  .then((result) => {
    if (result.status !== 202) {
      return Promise.reject(result)
    } else {
      console.log("Job ID: " + result.body.id);
      console.log("Job URL: " + result.body.url);

      // get results asynchronously
      return getAsyncResult(`${url}&id=${result.body.id}`, 60 * 1000 /*check every minute*/, 100 /*max number of attempts*/).then(queryResult => {

        console.log(queryResult);
        return queryResult;
      });
    }
  })
  .catch(err => console.log(err));

function getBodyAndStatus(response) {
  return response.json().then(responceBody => {
    return {
      status: response.status,
      body: responceBody
    }
  });
}

Get results asynchronously

Here’s an example of how to get the batcher job status and return results:

function getAsyncResult(url, timeout, maxAttempt) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      repeatUntilSuccess(resolve, reject, 0)
    }, timeout);
  });

  function repeatUntilSuccess(resolve, reject, attempt) {
    console.log("Attempt: " + attempt);
    fetch(url)
      .then(getBodyAndStatus)
      .then(result => {
        if (result.status === 200) {
          resolve(result.body);
        } else if (attempt >= maxAttempt) {
          reject("Max amount of attempts achived");
        } else if (result.status === 202) {
          // Check again after timeout
          setTimeout(() => {
            repeatUntilSuccess(resolve, reject, attempt + 1)
          }, timeout);
        } else {
          // Something went wrong
          reject(result.body)
        }
      })
      .catch(err => reject(err));
  };
}

Batch geocode postcodes

You can use the API to batch geocode addresses by setting type=postcode. In addition, we recommend setting a country filter when searching for a postcode to limit the results to a specific country.

In the rest, the postcodes lookup is similar to addresses lookup.

Postcodes in France to geocode

Let’s geocode these French postcodes and get the latitude and longitude coordinates in one batch:

const postcodes = [
    "27180",
    "27021",
    "27190",
    "27850",
    "27109",
    "27520",
    "27890",
    "27310",
    "27290",
    "27800"
];

In order to search postcodes in France only, set the type=postcode and filter=countrycode:fr:

const url = "https://api.geoapify.com/v1/batch/geocode/search?type=postcode&filter=countrycode:fr&apiKey=YOUR_API_KEY";

fetch(url, {
    method: 'post',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
  })
  .then(getBodyAndStatus)
  .then((result) => {
    if (result.status !== 202) {
      return Promise.reject(result)
    } else {
      console.log("Job ID: " + result.body.id);
      console.log("Job URL: " + result.body.url);
      return getAsyncResult(`${url}&id=${result.body.id}`, 1000, 100).then(queryResult => {
        console.log(queryResult);
        return queryResult;
      });
    }
  })
  .catch(err => console.log(err));