Skip to content

Geocoding and Districting

by Evan Callahan on May 18th, 2010

Groundwire’s latest project on Code Share is Geocoding and Districting. It uses address information to look up the latitude, longitude, congressional district, and state legislative districts for each contact and account entered into Salesforce.

I got the idea for this when I discovered Mobile Commons‘ free web service for looking up district information. Because I know that many nonprofits – including a number of Groundwire’s clients – pay significant fees to obtain this information, I was motivated to find out if I could retrieve it automatically.

The code was interesting to write for a few reasons:

  • There are two steps. First, you have to combine the full address and us it to look up the latitude and longitude. I used a web service called, which has both free and premium versions (free is limited to one lookup every 15 seconds). Then you send the latitude and longitude to the Mobile Commons web service to get the districts. I created a separate Apex class for each of these integrations.
  • I took advantage of the new built-in DOM support for XML district data, which is said to be faster and simpler than the older XMLDom class. (I actually found the new support to be sadly lacking in many ways, but I later found this nifty class which fills in the gaps.)
  • Because external callouts can’t be called directly from a trigger, I had to use the Apex @future notation to call the web services asynchronously. The coding happens a few seconds after you save a record, so you have to refresh the browser to see the result.
  • Calling out to a web service offers plenty of opportunities for error. In order to make my classes easier to use, I masked the complexity by handling all errors the same way, whether they were errors reported by the webservice, errors encountered during the callout process, or Apex exceptions. In every case, I simply set a string property called Error and failed gracefully; this makes the class much easier to use. In my trigger, I save any errors I receive in fields on Contact or Account, so you can see whether the geocoding and districting were successfully (or why not).
// example of how to find the district from the lat/lng
GW_MobileCommons mc = new GW_MobileCommons();
mc.latitude = 48;
mc.longitude = -122;
if (mc.error == null) {
   system.debug('Federal Congressional: ' + mc.congress);
   system.debug('State Senate: ' + mc.stateSenate);
   system.debug('State House: ' + mc.stateHouse);
} else {
   system.debug('ERROR: ' + mc.error);

If you visit the Code Share page to grab the source code, you’ll also find an AppExchange package link that allows you to install these tools directly into your own Salesforce instance. Please note the configuration steps: you have to add the two web service URLs to your Network Sites list before this will work. Also note that there are custom settings you can modify, which let you turn off the trigger for one or more actions.

Apex limits your web callouts to 10 at a time (and the free geocoding service limits them to just one), so this trigger isn’t going to work during a bulk data import or update. But when entering one record at a time, this is a great way to ensure that you have the geocoding and district information right away – and without any charge for the service.

One Comment
  1. Matt Hicks permalink

    Hi Evan,
    This is amazing stuff. I work for a non-profit that lobby’s for the Outdoor Industry. We are using Salesforce. I wanted to see if you could give me a hand if it isn’t too much work. I am not a coder at all and I am trying to read through your code to find out where I can take out of the code. I already have my own geolocation field called primary location. It already combines latitude and longitude into 1 field. ie. Primary Location:
    43.06714 -77.569165. Where would I put this field into your code to get rid of all the callouts and inputs? Any help would be much appreciated. Thanks! -Matt Hicks

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS