7 min read

(For more resources related to this topic, see here.)

Obtaining the Google API key

First, you need to obtain an API key for the Google Geocoding API:

  1. Visit https://code.google.com/apis/console and sign in with your Google account (assuming you already have one).
  2. Click on the Create Project button.
  3. Enter My Salesforce Account Project for the Project name.
  4. Accept the default value for the Project ID.
  5. Click on Create.
  6. Click on APIs & auth from the left-hand navigation bar.
  7. Set the Geocoding API to ON.

  8. Select Credentials and click on CREATE NEW KEY.
  9. Click on the Browser Key button.
  10. Click on Create to generate the key. Make a note of the API key.

Adding a Salesforce remote site

Now, we need to add a Salesforce remote site for the Google Maps API:

  1. Navigate to Setup | Security Controls | Remote Site Settings.
  2. Click on the New Remote Site button.
  3. Enter Google_Maps_API for the Remote Site Name.
  4. Enter https://maps.googleapis.com for the Remote Site URL.
  5. Ensure that the Active checkbox is checked.
  6. Click on Save.
  7. Your remote site detail should resemble the following screenshot:

Adding the Location custom field to Account

Next, we need to add a Location field to the Account object:

  1. Navigate to Setup | Customize | Accounts | Fields.
  2. Click on the New button in the Custom Fields & Relationships section.
  3. Select Geolocation for the Data Type. Click on Next.
  4. Enter Location for the Field Label. The Field Name should also default to Location.
  5. Select Decimal for the Latitude and Longitude Display Notation.
  6. Enter 7 for the Decimal Places. Click on Next.
  7. Click on Next to accept the defaults for Field-Level Security.
  8. Click on Save to add the field to all account related page layouts.

Adding the Apex Utility Class

Next, we need an Apex utility class to geocode an address using the Google Geocoding API:

  1. Navigate to Setup | Develop | Apex Classes.
  2. All of the Apex classes for your organization will be displayed. Click on Developer Console.
  3. Navigate to File | New | Apex Class.
  4. Enter AccountGeocodeAddress for the Class Name and click on OK.
  5. Enter the following code into the Apex Code Editor in your Developer Console window:

    // static variable to determine if geocoding has already occurred private static Boolean geocodingCalled = false; // wrapper method to prevent calling future methods from an existing future context public static void DoAddressGeocode(id accountId) {   if (geocodingCalled || System.isFuture()) {     System.debug(LoggingLevel.WARN, '***Address Geocoding Future Method Already Called - Aborting...');     return;   }   // if not being called from future context, geocode the address   geocodingCalled = true;   geocodeAddress(accountId); }

  6. The AccountGeocodeAddress method and public static variable geocodingCalled protect us from a potential error where a future method may be called from within a future method that is already executing. If this isn’t the case, we call the geocodeAddress method that is defined next. Enter the following code into the Apex Code Editor in your Developer Console window:

    // we need a future method to call Google Geocoding API from Salesforce @future (callout=true) static private void geocodeAddress(id accountId) {   // Key for Google Maps Geocoding API   String geocodingKey = '[Your API Key here]';   // get the passed in address   Account geoAccount = [SELECT BillingStreet, BillingCity, BillingState, BillingCountry, BillingPostalCode     FROM Account     WHERE id = :accountId];       // check that we have enough information to geocode the address   if ((geoAccount.BillingStreet == null) || (geoAccount.BillingCity == null)) {     System.debug(LoggingLevel.WARN, 'Insufficient Data to Geocode Address');     return;   }   // create a string for the address to pass to Google Geocoding API   String geoAddress = '';   if (geoAccount.BillingStreet != null)     geoAddress += geoAccount.BillingStreet + ', ';   if (geoAccount.BillingCity != null)     geoAddress += geoAccount.BillingCity + ', ';   if (geoAccount.BillingState != null)     geoAddress += geoAccount.BillingState + ', ';   if (geoAccount.BillingCountry != null)     geoAddress += geoAccount.BillingCountry + ', ';   if (geoAccount.BillingPostalCode != null)     geoAddress += geoAccount.BillingPostalCode;     // encode the string so we can pass it as part of URL   geoAddress = EncodingUtil.urlEncode(geoAddress, 'UTF-8');   // build and make the callout to the Geocoding API   Http http = new Http();   HttpRequest request = new HttpRequest();   request.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address='     + geoAddress + '&key=' + geocodingKey     + '&sensor=false');   request.setMethod('GET');   request.setTimeout(60000);   try {     // make the http callout     HttpResponse response = http.send(request);     // parse JSON to extract co-ordinates     JSONParser responseParser = JSON.createParser(response.getBody());     // initialize co-ordinates     double latitude = null;     double longitude = null;     while (responseParser.nextToken() != null) {       if ((responseParser.getCurrentToken() == JSONToken.FIELD_NAME) &&       (responseParser.getText() == 'location')) {         responseParser.nextToken();         while (responseParser.nextToken() != JSONToken.END_OBJECT) {           String locationText = responseParser.getText();           responseParser.nextToken();           if (locationText == 'lat')             latitude = responseParser.getDoubleValue();           else if (locationText == 'lng')             longitude = responseParser.getDoubleValue();         }       }     }     // update co-ordinates on address if we get them back     if (latitude != null) {       geoAccount.Location__Latitude__s = latitude;       geoAccount.Location__Longitude__s = longitude;       update geoAccount;     }   } catch (Exception e) {     System.debug(LoggingLevel.ERROR, 'Error Geocoding Address - ' + e.getMessage());   } }

  7. Insert your Google API key in the following line of code:

    String geocodingKey = '[Your API Key here]';

  8. Navigate to File | Save.

Adding the Apex Trigger

Finally, we need to implement an Apex trigger class to geocode the Billing Address when an Account is added or updated

  1. Navigate to Setup | Develop | Apex Triggers.
  2. All of the Apex triggers for your organization will be displayed. Click on Developer Console.
  3. Navigate to File | New | Apex Trigger in the Developer Console.
  4. Enter geocodeAccountAddress in the Name field.
  5. Select Account in the Objects dropdown list and click on Submit.
  6. Enter the following code into the Apex Code Editor in your Developer Console window:

    trigger geocodeAccountAddress on Account (after insert, after update) {       // bulkify trigger in case of multiple accounts   for (Account account : trigger.new) {       // check if Billing Address has been updated     Boolean addressChangedFlag = false;     if (Trigger.isUpdate) {       Account oldAccount = Trigger.oldMap.get(account.Id);       if ((account.BillingStreet != oldAccount.BillingStreet) ||       (account.BillingCity != oldAccount.BillingStreet) ||         (account.BillingCountry != oldAccount.BillingCountry) ||         (account.BillingPostalCode != oldAccount.BillingPostalCode)) {           addressChangedFlag = true;           System.debug(LoggingLevel.DEBUG, '***Address changed for - ' + oldAccount.Name);       }     }     // if address is null or has been changed, geocode it     if ((account.Location__Latitude__s == null) || (addressChangedFlag == true)) {       System.debug(LoggingLevel.DEBUG, '***Geocoding Account - ' + account.Name);       AccountGeocodeAddress.DoAddressGeocode(account.id);     }   } }

  7. Navigate to File | Save.

The after insert / after update account trigger itself is relatively simple. If the Location field is blank, or the Billing Address has been updated, a call is made to the AccountGeocodeAddress.DoAddressGeocode method to geocode the address against the Google Maps Geocoding API.

Summary

Congratulations, you have now completed the Geolocation trigger for your Salesforce Account Object. With this, we can calculate distances between two objects in Salesforce or search for accounts/contacts within a certain radius.

Resources for Article:


Further resources on this subject:


2 COMMENTS

  1. Hello

    I tried your tuto in my sandbox,

    But I’ve some error. I thinks it’s because of return lines into your code. Like “//”
    And I don’t have a name of geocodeAddress in point 6.
    Could you send me the 3 classes by txt file?

    Kind Regards

    Benoit

  2. public class AccountGeocodeAddress {
    // static variable to determine if geocoding has already occurred
    private static Boolean geocodingCalled = false;
    // wrapper method to prevent calling future methods from an existing future context
    public static void DoAddressGeocode (id accountId){
    system.debug(‘Called’);
    if (geocodingCalled || System.isFuture()) {
    System.debug(LoggingLevel.WARN,’***Address Geocoding Future Method Already Called – Aborting…’);
    return;
    }
    // if not being called from future context, geocode the address
    geocodingCalled = true;
    geocodeAddress(accountId);
    }
    // we need a future method to call Google Geocoding API from Salesforce
    @future (callout=true)
    static private void geocodeAddress(id accountId){
    // Key for Google Maps Geocoding API
    String geocodingKey = ‘Your API Key Value’;
    // get the passed in address
    Account geoAccount = [SELECT BillingStreet, BillingCity, BillingState, BillingCountry,
    BillingPostalCode,Locations__Latitude__s,Locations__Longitude__s
    FROM
    Account
    WHERE
    id = :accountId];

    // check that we have enough information to geocode the address
    if((geoAccount.BillingStreet == null) || (geoAccount.BillingCity == null)) {
    System.debug(LoggingLevel.WARN,
    ‘Insufficient Data to Geocode Address’);
    return;
    }
    // create a string for the address to pass to Google Geocoding API
    String geoAddress = ”;
    if(geoAccount.BillingStreet != null)
    geoAddress += geoAccount.BillingStreet + ‘, ‘;
    if(geoAccount.BillingCity != null)
    geoAddress+= geoAccount.BillingCity + ‘, ‘;
    if(geoAccount.BillingState != null)
    geoAddress+= geoAccount.BillingState + ‘, ‘;
    if(geoAccount.BillingCountry != null)
    geoAddress+= geoAccount.BillingCountry + ‘, ‘;
    if(geoAccount.BillingPostalCode != null)
    geoAddress+= geoAccount.BillingPostalCode;

    // encode the string so we can pass it as part of URL
    geoAddress = EncodingUtil.urlEncode(geoAddress, ‘UTF-8’);
    // build and make the callout to the Geocoding API
    Http http = new Http();
    HttpRequest request = new HttpRequest();
    request.setEndpoint(‘https://maps.googleapis.com/maps/api/geocode/json?address=’+geoAddress + ‘&key=’ + geocodingKey+ ‘&sensor=false’);
    request.setMethod(‘GET’);
    request.setTimeout(60000);
    //try {
    // make the http callout
    HttpResponse response = http.send(request);
    // parse JSON to extract co-ordinates
    JSONParser responseParser = JSON.createParser(response.getBody());
    // initialize co-ordinates

    System.debug(‘JSONParser$$’+responseParser);
    double latitude = null;
    double longitude = null;
    while (responseParser.nextToken() != null) {
    System.debug(‘currentToken!!’+responseParser.getCurrentToken());
    System.debug(‘NextToken!!’+responseParser.nextToken());
    System.debug(‘text@@’+responseParser.getText());
    System.debug(‘JSOn!!’+JSONToken.FIELD_NAME +’###’+JSONToken.END_OBJECT);
    if((responseParser.getCurrentToken() == JSONToken.FIELD_NAME)) {
    responseParser.nextToken();

    while(responseParser.nextToken() != JSONToken.END_OBJECT) {

    String locationText = responseParser.getText();

    responseParser.nextToken();

    if (locationText == ‘lat’)

    latitude = responseParser.getDoubleValue();

    else if (locationText == ‘lng’)

    longitude = responseParser.getDoubleValue();
    }
    }
    }
    // update co-ordinates on address if we get them back
    if(latitude != null) {
    System.debug(‘!!’+latitude);
    System.debug(‘@@’+longitude);
    geoAccount.Locations__Latitude__s
    = latitude;
    geoAccount.Locations__Longitude__s
    = longitude;
    update geoAccount;
    }
    /* } catch
    (Exception e) {
    System.debug(LoggingLevel.ERROR, ‘Error Geocoding Address – ‘ + e.getMessage());
    }*/
    }

    }

LEAVE A REPLY

Please enter your comment!
Please enter your name here