Monitor your key's usage before you hit a limit
Watching your quota headers as you go tells you when a limit is approaching, well before a request actually gets rejected.
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.
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": {}}
]
}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.
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.
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.
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.
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.
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.
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.