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.
- Authentication and API key
- Forward Batch API reference
- Reverse Batch API reference
- Code samples
- Pricing
Authentication 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 reference
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 reference
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));
Pricing
Geoapify Location Platform provides APIs which have different difficulty, execution times and require different resource capacities on our servers.
To make our pricing plans easy-to-understand and unify them we introduced "credits" currency that is used to describe conditions and options of each pricing plan. All the credits used for Geoapify API calls per 24 hours accumulated to Daily API usage.
Check Geoapify Pricing Plans and choose the one that fits your needs the best.
One Geocoding API / Reverse Geocoding API / Autocomplete API request is equal to one credit:
API name | Cost in credits | Example |
---|---|---|
Geocoding API | 1 request = 1 credit | 100 requests costs 100 credits |
Reverse Geocoding API | 1 request = 1 credit | 100 requests costs 100 credits |
Address Autocomplete | 1 request = 1 credit | 100 requests costs 100 credits |
You can save up to 50% of API call costs when you send Batch Geocoding requests.