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 CRM export is usually a flat file of customer records with an address field and nothing else location-related, no coordinates, no verified components. Turning that into something you can map or segment regionally means geocoding the whole export.
Pull the address column out of your CRM export as a plain array, keeping the customer ID aligned with each address by position, since you will need to match results back to records afterward.
POST /v1/forward
Content-Type: application/json
["1600 Pennsylvania Avenue, Washington", "221B Baker Street, London"]{
"status": "ok",
"results": [
{"formatted": "1600 Pennsylvania Avenue NW, Washington, DC 20500", "lat": 38.8977, "lon": -77.0365, "type": "address", "precision": "house", "confidence": 0.97, "place_id": "def456", "components": {}},
{"formatted": "221B Baker Street, London, UK", "lat": 51.5237, "lon": -0.1585, "type": "address", "precision": "house", "confidence": 0.95, "place_id": "abc123", "components": {}}
]
}Match each result to its customer by the position you tracked before sending the request, then write the coordinates and components back into your CRM either through its own API or a bulk import, depending on what your CRM supports. Store the confidence and precision fields too, so anything with a weak match can be flagged for cleanup rather than treated as verified.
A CRM with customers across several countries benefits from passing the countries parameter alongside each region's batch, restricting candidate matches to the expected country and cutting down on the rare case where a street name common in more than one country resolves to the wrong one. Splitting the export into per-country batches before sending each as its own bulk request is a reasonable way to apply this without changing anything else about the workflow.
Do not deduplicate or reorder the address array before sending it without keeping a separate mapping back to the original customer IDs. Results return in the same order as the array you sent, and once that order is decoupled from your customer records without a saved index, there is no reliable way to match a coordinate pair back to the right customer afterward. Keep the position-to-ID mapping in memory or in a temporary column for the duration of the job.
Once the initial export is geocoded, there is no need to reprocess the whole customer base again later. Track which records already have coordinates and only send new or address-updated records through the endpoint on subsequent runs, keeping ongoing request usage proportional to new activity rather than your total customer count.
A record with a low confidence score or missing several expected components is worth flagging in a review queue rather than writing silently alongside your fully verified records. This keeps a bad address from quietly contaminating a regional report or a map view built from the backfilled data.
A one-time backfill of an existing CRM costs one request per customer record with an address, run as a single bulk call or a handful of chunks. A CRM with a few thousand customers might use more than the 2,500 free requests a day in one sitting, which is a reasonable moment to either spread the job across a couple of days or move onto prepaid credit for a one-time push.
Once the backfill is done, ongoing geocoding for new customers is small and steady rather than a recurring bulk job. See the forward geocoding docs for the full request and response shape.