Google's Geocoder returns wrong country, ignoring the region hint
Asked Answered
S

13

31

I'm using Google's Geocoder to find lat lng coordinates for a given address.

    var geocoder = new google.maps.Geocoder();
    geocoder.geocode(
    {
        'address':  address,
        'region':   'uk'
    }, function(results, status) {
        if(status == google.maps.GeocoderStatus.OK) {
            lat: results[0].geometry.location.lat(),
            lng: results[0].geometry.location.lng()
    });

address variable is taken from an input field.

I want to search locations only in UK. I thought that specifying 'region': 'uk' should be enough but it's not. When I type in "Boston" it's finding Boston in US and I wanted the one in UK.

How to restrict Geocoder to return locations only from one country or maybe from a certain lat lng range?

Thanks

Sudorific answered 15/4, 2010 at 16:20 Comment(0)
C
22

UPDATE: This answer may not be the best approach anymore. See the comments below the answer for more details.


In addition to what Pekka already suggested, you may want to concatenate ', UK' to your address, as in the following example:

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps Geocoding only in UK Demo</title> 
   <script src="http://maps.google.com/maps/api/js?sensor=false" 
           type="text/javascript"></script> 
</head> 
<body> 
   <div id="map" style="width: 400px; height: 300px"></div> 

   <script type="text/javascript"> 

   var mapOptions = { 
      mapTypeId: google.maps.MapTypeId.TERRAIN,
      center: new google.maps.LatLng(54.00, -3.00),
      zoom: 5
   };

   var map = new google.maps.Map(document.getElementById("map"), mapOptions);
   var geocoder = new google.maps.Geocoder();

   var address = 'Boston';

   geocoder.geocode({
      'address': address + ', UK'
   }, 
   function(results, status) {
      if(status == google.maps.GeocoderStatus.OK) {
         new google.maps.Marker({
            position:results[0].geometry.location,
            map: map
         });
      }
   });

   </script> 
</body> 
</html>

Screenshot:

Geocoding only in UK

I find that this is very reliable. On the other hand, the following example shows that neither the region parameter, nor the bounds parameter, are having any effect in this case:

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps Geocoding only in UK Demo with Bounds</title> 
   <script src="http://maps.google.com/maps/api/js?sensor=false" 
           type="text/javascript"></script> 
</head> 
<body> 
   <div id="map" style="width: 500px; height: 300px"></div> 

   <script type="text/javascript"> 

   var mapOptions = { 
      mapTypeId: google.maps.MapTypeId.TERRAIN,
      center: new google.maps.LatLng(50.00, -33.00),
      zoom: 3
   };

   var map = new google.maps.Map(document.getElementById("map"), mapOptions);   
   var geocoder = new google.maps.Geocoder();

   // Define north-east and south-west points of UK
   var ne = new google.maps.LatLng(60.00, 3.00);
   var sw = new google.maps.LatLng(49.00, -13.00);

   // Define bounding box for drawing
   var boundingBoxPoints = [
      ne, new google.maps.LatLng(ne.lat(), sw.lng()),
      sw, new google.maps.LatLng(sw.lat(), ne.lng()), ne
   ];

   // Draw bounding box on map    
   new google.maps.Polyline({
      path: boundingBoxPoints,
      strokeColor: '#FF0000',
      strokeOpacity: 1.0,
      strokeWeight: 2,
      map: map
   });

   // Geocode and place marker on map
   geocoder.geocode({
      'address': 'Boston',
      'region':  'uk',
      'bounds':  new google.maps.LatLngBounds(sw, ne)
   }, 
   function(results, status) {
      if(status == google.maps.GeocoderStatus.OK) {
         new google.maps.Marker({
            position:results[0].geometry.location,
            map: map
         });
      }
   });

   </script> 
</body> 
</html>
Cockoftherock answered 15/4, 2010 at 16:31 Comment(12)
This is what I would call a "dirty fix" but I think I'll have to do that :/Sudorific
@6bytes: It may be a hack, but I still have to find a case where it does not work.Cockoftherock
Quite a bug we've found here :) I hope Google knows about this and will fix it soon.Sudorific
You might also want to post this in the public Google Maps API help forum at groups.google.com/group/google-maps-api/topics (if you haven't done so already :-)).Griffen
@John: Thanks for the tip. I just did a quick search in the Google Groups and found a similar post: groups.google.com/group/google-maps-js-api-v3/browse_thread/….Cockoftherock
@Daniel: I am using exactly the same hack (go figure) but I am at this page because I found a case where it does not work. Looking for 'Brasilia, PT', should show something with 'brasilia' in portugal (there are plenty of avenues), but is shows something with portugal in brasil. :-)Colure
Between Pekka's and Ivo Bosticky's answers you have the full reasons for and solution to this problem. There is no need for this 'dirty fix'. The region parameter is only a bias for results - so if you want results limited to a specific region - check to see if there is a result for that region (as per Ivo Bosticky's answer)Intarsia
@DanielVassallo Gecoding is not a science - the results it gives are not wrong at all. On the contrary you are using the first result of the query unchecked which is simply bad programming. The api provides the means to check where is the result is located, so if you want UK results check for them to avoid this horrible kludge.Intarsia
@Intarsia : The answer was posted a very long time ago... From what I remember, the results back then did not include the "other" place, so if you searched for "Boston", you'd get a result-set representing "Boston, USA" with the results ordered in "reverse-precision order" (so, the first result would often be at street-level precision, the second at city-level, then at country, etc). Things may have changed since then, so if I find some time I'll try to verify this again, and update my answer as necessary. Thanks for your comments!Cockoftherock
@Intarsia : In addition, the Google Docs still describe the bounds argument as the "LatLngBounds within which to search. Optional." I think that my answer showed that in April 2010, this argument was just a bias at most, and not restricting the search as the docs seem to say.Cockoftherock
Adding "UK" to the query will work in many cases, but as pointed out by nickthompson it can give you problems. The Geocoding API (and recently the JavaScript API too) have a better approach: use componentRestrictions (as pointed out by Yenya)Eldwin
whilst @Eldwin you have a point, in some cases the componentRestriction is not giving the desired response. For example if the user enters a spurious address such as "glglbljhglhglbj", with componentRestriction set to "UK" then geocoder will default this address to the centre of the UK. However, if we append ", UK" to the address, as this answer suggests, then zero results are (rightly) returned. I can also confirm that the address "Boston" returns the Boston in the UK now, not the Boston in the USA.Timbered
N
28

Use componentRestrictions attribute:

geocoder.geocode({'address': request.term, componentRestrictions: {country: 'GB'}}
Nanoid answered 8/11, 2013 at 10:25 Comment(4)
This works to get "Clevedon" to return the town in Zn instead of England, but when I search for a non-existent address it returns the result of the whole country (as per spec) instead of ZERO_RESULTS.Safford
Returning the whole country is what's expected: "If no matches are found, the geocoder will return a result that matches the filter itself." -- developers.google.com/maps/documentation/geocoding/…Eldwin
The best solution I have tried, returning relative results and only for the specified country! Mentioned componentRestrictions in other functions, however undocumented for Geocoder.Outgrowth
Documentation states that the country field "matches a country name or a two letter ISO 3166-1 country code". The ISO code for united Kingdom is GB however UK will also work.Spangle
A
27

The following code will get the first matching address in the UK without the need to modify the address.

  var geocoder = new google.maps.Geocoder();
  geocoder.geocode(
  {
    'address':  address,
    'region':   'uk'
  }, function(results, status) {
    if(status == google.maps.GeocoderStatus.OK) {
        for (var i=0; i<results.length; i++) {
            for (var j=0; j<results[i].address_components.length; j++) {
               if ($.inArray("country", results[i].address_components[j].types) >= 0) {
                    if (results[i].address_components[j].short_name == "GB") {
                        return_address = results[i].formatted_address;
                        return_lat = results[i].geometry.location.lat();
                        return_lng = results[i].geometry.location.lng();
                        ...
                        return;
                    }
                }
            }
        }
    });
Appointment answered 1/2, 2012 at 14:16 Comment(6)
I think you are the only person who has answered this in the way the api is intended to be used. Setting a bias as documented - but then actually checking the results to see if there is a preferred match.Intarsia
Yes, this is the best answer! Adding ", UK" or ", US" can actually have the unintended effect of searching street addresses and not locations; it's much better to assume you can get multiple results back and search to find the one in the region you want.Edge
My search for "Clevedon" only returns one result no matter what I do. Even with the bias set to NZ it returns a single result from the UK, adding ", NZ" to the address returns the result from New Zealand, but I can't get both results and use this scan technique to trim down to the one I want.Safford
What's the third for-loop for? I can't see k being used anywhere and the types.length doesn't related to the short name value.Safford
Updated the code to use inArray function to verify that the address_component is of type "country". The original code used a loop with variable k, but the actual check for address_component[j].type[k] == "country" was missing.Appointment
This was the best you could do in Feb 2012, but nowadays you should be using componentRestrictions, added to the JavaScript API in July 2013.Eldwin
C
22

UPDATE: This answer may not be the best approach anymore. See the comments below the answer for more details.


In addition to what Pekka already suggested, you may want to concatenate ', UK' to your address, as in the following example:

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps Geocoding only in UK Demo</title> 
   <script src="http://maps.google.com/maps/api/js?sensor=false" 
           type="text/javascript"></script> 
</head> 
<body> 
   <div id="map" style="width: 400px; height: 300px"></div> 

   <script type="text/javascript"> 

   var mapOptions = { 
      mapTypeId: google.maps.MapTypeId.TERRAIN,
      center: new google.maps.LatLng(54.00, -3.00),
      zoom: 5
   };

   var map = new google.maps.Map(document.getElementById("map"), mapOptions);
   var geocoder = new google.maps.Geocoder();

   var address = 'Boston';

   geocoder.geocode({
      'address': address + ', UK'
   }, 
   function(results, status) {
      if(status == google.maps.GeocoderStatus.OK) {
         new google.maps.Marker({
            position:results[0].geometry.location,
            map: map
         });
      }
   });

   </script> 
</body> 
</html>

Screenshot:

Geocoding only in UK

I find that this is very reliable. On the other hand, the following example shows that neither the region parameter, nor the bounds parameter, are having any effect in this case:

<!DOCTYPE html>
<html> 
<head> 
   <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
   <title>Google Maps Geocoding only in UK Demo with Bounds</title> 
   <script src="http://maps.google.com/maps/api/js?sensor=false" 
           type="text/javascript"></script> 
</head> 
<body> 
   <div id="map" style="width: 500px; height: 300px"></div> 

   <script type="text/javascript"> 

   var mapOptions = { 
      mapTypeId: google.maps.MapTypeId.TERRAIN,
      center: new google.maps.LatLng(50.00, -33.00),
      zoom: 3
   };

   var map = new google.maps.Map(document.getElementById("map"), mapOptions);   
   var geocoder = new google.maps.Geocoder();

   // Define north-east and south-west points of UK
   var ne = new google.maps.LatLng(60.00, 3.00);
   var sw = new google.maps.LatLng(49.00, -13.00);

   // Define bounding box for drawing
   var boundingBoxPoints = [
      ne, new google.maps.LatLng(ne.lat(), sw.lng()),
      sw, new google.maps.LatLng(sw.lat(), ne.lng()), ne
   ];

   // Draw bounding box on map    
   new google.maps.Polyline({
      path: boundingBoxPoints,
      strokeColor: '#FF0000',
      strokeOpacity: 1.0,
      strokeWeight: 2,
      map: map
   });

   // Geocode and place marker on map
   geocoder.geocode({
      'address': 'Boston',
      'region':  'uk',
      'bounds':  new google.maps.LatLngBounds(sw, ne)
   }, 
   function(results, status) {
      if(status == google.maps.GeocoderStatus.OK) {
         new google.maps.Marker({
            position:results[0].geometry.location,
            map: map
         });
      }
   });

   </script> 
</body> 
</html>
Cockoftherock answered 15/4, 2010 at 16:31 Comment(12)
This is what I would call a "dirty fix" but I think I'll have to do that :/Sudorific
@6bytes: It may be a hack, but I still have to find a case where it does not work.Cockoftherock
Quite a bug we've found here :) I hope Google knows about this and will fix it soon.Sudorific
You might also want to post this in the public Google Maps API help forum at groups.google.com/group/google-maps-api/topics (if you haven't done so already :-)).Griffen
@John: Thanks for the tip. I just did a quick search in the Google Groups and found a similar post: groups.google.com/group/google-maps-js-api-v3/browse_thread/….Cockoftherock
@Daniel: I am using exactly the same hack (go figure) but I am at this page because I found a case where it does not work. Looking for 'Brasilia, PT', should show something with 'brasilia' in portugal (there are plenty of avenues), but is shows something with portugal in brasil. :-)Colure
Between Pekka's and Ivo Bosticky's answers you have the full reasons for and solution to this problem. There is no need for this 'dirty fix'. The region parameter is only a bias for results - so if you want results limited to a specific region - check to see if there is a result for that region (as per Ivo Bosticky's answer)Intarsia
@DanielVassallo Gecoding is not a science - the results it gives are not wrong at all. On the contrary you are using the first result of the query unchecked which is simply bad programming. The api provides the means to check where is the result is located, so if you want UK results check for them to avoid this horrible kludge.Intarsia
@Intarsia : The answer was posted a very long time ago... From what I remember, the results back then did not include the "other" place, so if you searched for "Boston", you'd get a result-set representing "Boston, USA" with the results ordered in "reverse-precision order" (so, the first result would often be at street-level precision, the second at city-level, then at country, etc). Things may have changed since then, so if I find some time I'll try to verify this again, and update my answer as necessary. Thanks for your comments!Cockoftherock
@Intarsia : In addition, the Google Docs still describe the bounds argument as the "LatLngBounds within which to search. Optional." I think that my answer showed that in April 2010, this argument was just a bias at most, and not restricting the search as the docs seem to say.Cockoftherock
Adding "UK" to the query will work in many cases, but as pointed out by nickthompson it can give you problems. The Geocoding API (and recently the JavaScript API too) have a better approach: use componentRestrictions (as pointed out by Yenya)Eldwin
whilst @Eldwin you have a point, in some cases the componentRestriction is not giving the desired response. For example if the user enters a spurious address such as "glglbljhglhglbj", with componentRestriction set to "UK" then geocoder will default this address to the centre of the UK. However, if we append ", UK" to the address, as this answer suggests, then zero results are (rightly) returned. I can also confirm that the address "Boston" returns the Boston in the UK now, not the Boston in the USA.Timbered
R
16

The correct way of doing this is by providing componentRestrictions

For example:

var request = {
    address: address,
    componentRestrictions: {
        country: 'UK'
    }
}
geocoder.geocode(request, function(results, status){
    //...
});
Resilience answered 27/2, 2014 at 22:26 Comment(0)
V
8

According to the docs, the region parameter seems to set a bias only (instead of a real limit to that region). I guess when the API doesn't find the exact address in the UK place, it will expand it search no matter what region you enter.

I've fared pretty well in the past with specifying the country code in the address (in addition to the region). I haven't had much experience with identical place names in different countries yet, though. Still, it's worth a shot. Try

'address': '78 Austin Street, Boston, UK'

it should return no address (Instead of the US Boston), and

'address': '78 Main Street, Boston, UK'

Should return the Boston in the UK because that actually has a Main Street.

Update:

How to restrict Geocoder to return locations only from one country or maybe from a certain lat lng range?

You can set a bounds parameter. See here

You would have to calculate a UK-sized rectangle for that, of course.

Volta answered 15/4, 2010 at 16:26 Comment(12)
Typing in "Boston" returns the one in US, typing in "Boston, UK" returns the one in UK. Why if I'm connecting from Europe a US based location is returned first? I can't force my users to type in country code :(Sudorific
@Pekka, I tried geocoding 78 Austin Street, Boston, UK just for curiosity, but it returned some random 'Austin Avenue' close to Manchester. Google Maps Link: maps.google.com/…Cockoftherock
@Daniel that's odd. I get a clear "address not found" when I type in that address in Google Maps. (A geocoding result should come with an extremely low accuracy value.)Volta
@6bytes: I think that in case of ambiguity, Google tends to select the most popular city (This was discussed on Stack Overflow once: it looks like it chooses the one with the biggest population). Obviously the region parameter should be returning the UK city, but apparently it is not reliable yet. The only reliable way I am aware of at the moment is to concatenate ', UK' to your address. If users add the country code and you add the UK part twice, it won't hurt either (even though you might want to check for that).Cockoftherock
@Pekka: Yes in the public Google Maps (maps.google.com). But try it out with the example in my answer, using the Maps API. The Google Maps API and the public Google Maps seem to use different data sets sometimes. I've witnessed this a few times. In some places, even the imagery and the road maps are different.Cockoftherock
@Daniel interesting. I don't have a Maps API environment handy right now (I'm at work)... Can you see what accuracy you get for that address? Does that invalidate our approach (adding ,UK to the address)?Volta
@Pekka: Regarding the accuracy value, the version 3 of the Maps API (the one the OP is using apparently), is not returning an accuracy value anymore. It is using an enumaration of the GeocoderLocationType class: code.google.com/apis/maps/documentation/v3/…. Both return RANGE_INTERPOLATED. Using just Boston, UK returns APPROXIMATE. As you can see, this cannot be relied upon. I would have expected Boston, UK to return GEOMETRIC_CENTER, for example, and 78 Austin Street to return APPROXIMATE at least... or maybe WILD GUESS :).Cockoftherock
@Daniel cheers, good to know, I haven't had the opportunity to work with V3 yet. Hmm, crap. Then, there may be no way around either setting bounds in the request options (which would mean calculating a country rectangle) or checking the result for the country?Volta
@Pekka: There is according to the docs, but it is not reliable (at least at the moment). (code.google.com/apis/maps/documentation/v3/…). I tried setting the bounds to SW: 49.00, -13.00, NE: 60.00, 3.00, and the region to uk, but the Geocoder still returns the Boston in Massachusetts. The only reliable way around this that I am aware of is to ask the Geocoder for Boston, UK.Cockoftherock
@Pekka: Unfortunately the bounds parameter doesn't work as expected. Check the new example in my updated answer. This may be because of Google Maps v3 is still a Labs version, or else it just acting a hint, as you suggested initially. However the docs of version 3 do not seem to suggest that it is a hint: bounds is the LatLngBounds within which to search and region is the country code top-level domain within which to search.Cockoftherock
In my case, my country is Libya, using LY still returns results from United States, I appended 'Libya' to the search query and it's working just fine.Siegbahn
the bounds are identified in the answer by @nickthompson aboveTimbered
H
5

I found problems with putting ",UK", setting the region to UK and setting bounds. However, doing ALL THREE seems to fix it for me. Here's a snippet:-

var sw = new google.maps.LatLng(50.064192, -9.711914)
var ne = new google.maps.LatLng(61.015725, 3.691406)
var viewport = new google.maps.LatLngBounds(sw, ne);

geocoder.geocode({ 'address': postcode + ', UK', 'region': 'UK', "bounds": viewport }, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
.....etc.....
Happ answered 5/1, 2012 at 15:2 Comment(2)
I have tested the "bounds": viewport by itself and can confirm that it works perfectly. so does 'region': 'UK' and so for that reason I went with the latter. Thanks.Timbered
no in fact I'm wrong. I needed all three! For anyone not believing me, try the address "fsdfsdafsa" and you'll see that in fact it does return an address in the USA, even with region set to UK. I have now appended ", UK" to my 'address'. Thank you.Timbered
E
3

I tried with the following:

geocoder.geocode( {'address':request.term + ', USA'}

And its working for me for particular region (US country).

Errecart answered 27/2, 2012 at 4:39 Comment(0)
I
1

I always found this to be pretty easy to filter through since the results can vary and the region doesn't seem to work.

response( $.map( results, function( item ) {
 if (item.formatted_address.indexOf("GB") != -1) {
    return {
      latitude: item.geometry.location.lat(),
      longitude: item.geometry.location.lng()
    }
  }
}
Iyar answered 23/4, 2013 at 7:18 Comment(0)
U
0

For the united kingdom, you have to use GB for region. UK is not the ISO country code!

Unbonnet answered 24/3, 2011 at 19:44 Comment(2)
Actually the docs explicitly say you have to use UK: code.google.com/apis/maps/documentation/geocoding/#RegionCodes (it uses ccTLD, not ISO 3166-1).Swordplay
That link is for the geocoding service, not the JavaScript geocoder that this question is about. The JavaScript documentation at developers.google.com/maps/documentation/javascript/… states that ISO 3166-1 codes are supported too.Olmos
K
0

I prefer a hybrid approach.

  1. Use componentRestrictions to severely limit to country first.
  2. If that doesn't yield enough results, search more broadly (and re-introduce bias if necessary)

    function MyGeocoder(address,region)
    {
        geocoder = new google.maps.Geocoder();
        geocoder.geocode({ 'address': address, 'componentRestrictions': { 'country': region } }, function (r, s) {
            if (r.length < 10) geocoder.geocode({ 'address': address /* could also bias here */ }, function (r2, s2) {
                for (var j = 0; j < r2.length; j++) r.push(r2[j]);
                DoSomethingWithResults(r);
            });
            else DoSomethingWithResults(r);
        });
    }
    function DoSomethingWithResults(r) { // Remove Duplicates var d = {}; r = r.filter(function (e) { var h = e.formatted_address.valueOf(); var isDup = d[h]; d[h] = true; return !isDup; });

    // Do something with results }

Keijo answered 24/4, 2014 at 17:4 Comment(0)
D
0

I find that for a lot of ambiguous queries, the US always takes precedence in Google, even if you try to tell it where to look. You can look at the response and perhaps ignore it if output country=US?

That is the main reason I stopped using Google Geocoder a while ago and started building my own two years ago.

https://geocode.xyz/Boston,%20UK will always return the UK location. You can make extra sure by adding region=UK: https://geocode.xyz/Boston,%20UK?region=UK

Dinsmore answered 28/4, 2018 at 12:10 Comment(0)
R
0

I have Created Border All Around Uk and check if my Lat and Lng are in the Range. For 3 k addresses I have around 10 up to 20 addresses in US. I just Ignore them(I can do that in my case) I use lat and lng for creating multi markers on static map with auto zoom. I will share my Solution maybe this will be help for someone. Also I'm Happy to hear different Solutions for my case.

    private static string ReturnLatandLng(string GeocodeApiKey, string address)
    {
        string latlng = "";

        Geocoder geocoder = new Geocoder(GeocodeApiKey);

        var locations = geocoder.Geocode(address);

        foreach (var item in locations)
        {

            double longitude = item.LatLng.Longitude;
            double latitude = item.LatLng.Latitude;
            double borderSouthLatitude = 49.895878;
            double borderNorthLatitude = 62.000000;
            double borderWestLongitude = -8.207676;
            double borderEastLongitude = 2.000000;

            //Check If Geocoded Address is inside of the UK
            if (( (borderWestLongitude < longitude) && (longitude < borderEastLongitude) ) && ( (borderSouthLatitude < latitude) && (latitude < borderNorthLatitude) ) )
            {
                latlng = item.LatLng.ToString();
            }
            else
            {
                latlng = "";
                Console.WriteLine("GEOCODED ADDRESS IS NOT LOCATED IN UK ADDRESSES LIST. DELETING MARKER FROM MAP.....");
            }
        }
        return latlng;
    }
Rebate answered 15/3, 2019 at 11:6 Comment(0)
E
-1

I had to filter results to a country myself today. I found out that the two character country code in componentRestrictions:country: does not work. But the full country name does.

This is the full_name in the address_components from a result.

Existential answered 20/4, 2015 at 10:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.