Guides

Geocode a spreadsheet of addresses in one batch request

A spreadsheet full of addresses does not need a loop. Every My Geocode endpoint accepts a POST request with a JSON array in place of query parameters, and the forward geocoding endpoint will take a whole column of addresses at once, returning one geocoded result per row in the same order you sent them.

Building the request

Export the address column from your spreadsheet as a plain array of strings, then POST it to /v1/forward. Each array item is treated as its own lookup and returns its own result, in the same order you sent them.

POST /v1/forward
Content-Type: application/json

["221B Baker Street, London", "1600 Pennsylvania Avenue, Washington"]
{
  "status": "ok",
  "results": [
    {"formatted": "221B Baker Street, London, UK", "lat": 51.5237, "lon": -0.1585, "type": "address", "precision": "house", "confidence": 0.95, "place_id": "abc123", "components": {}},
    {"formatted": "1600 Pennsylvania Avenue, Washington, DC", "lat": 38.8977, "lon": -77.0365, "type": "address", "precision": "house", "confidence": 0.97, "place_id": "def456", "components": {}}
  ]
}

Narrowing results with a mixed country list

If your spreadsheet covers several countries, a plain array of strings still works, but ambiguous street names in different countries can end up resolved to the wrong one. Where your spreadsheet has a separate country column, send each country's rows as its own batch with the countries parameter set to the matching ISO code, rather than mixing countries into one call and hoping the address text alone disambiguates them.

What it costs

A bulk request is billed by the item, not by the call. Two addresses in one POST use two requests from your daily allowance, exactly as if you had sent two separate GET requests. A 500 row spreadsheet costs 500 requests, comfortably inside the 2,500 free requests a day that come with every key, or with no key at all.

Matching rows back up

Results come back in the same order as the array you sent, so keep the original row index next to each address before you send the request. Once the response arrives, match results back onto your spreadsheet rows by position, not by comparing text, since the formatted address in the response will rarely read identically to what you typed.

Handling partial failures

A row with a missing result, a low confidence score, or a precision below what you need should be flagged rather than accepted automatically. Check the confidence field on each item and route anything below your own threshold to a manual review list.

An edge case: blank rows

A spreadsheet export often carries a handful of entirely blank rows near the end of the file, left over from formatting or a filter that once included empty cells. An empty string in the array still counts as one item and typically returns an empty or very low confidence result, which then needs to be filtered before it reaches your data table, so trim blank rows out at export time rather than sending them through the batch at all.

A mistake worth avoiding

Sending the same address twice, once from an active customer list and again from an old export that never got cleaned up, is an easy way to burn through a chunk of your daily allowance on duplicate work. Deduplicate the address column before you build the array, and only re-run rows that changed since the last export, rather than re-geocoding an entire spreadsheet every time a handful of rows are added.

Splitting large files

Very large files are easier to manage in chunks of a few hundred to a few thousand rows. Chunking also makes it simple to check your quota headers between batches and stop before you run past your free allowance or prepaid credit.

If your spreadsheet has more than a handful of rows, this is the difference between one request and hundreds of round trips. The full request and response shape is documented on the forward geocoding page.