Get city name using geolocation [duplicate]
Asked Answered
D

12

162

I managed to get the user's latitude and longitude using HTML-based geolocation.

//Check if browser supports W3C Geolocation API
if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(successFunction, errorFunction);
} 
//Get latitude and longitude;
function successFunction(position) {
    var lat = position.coords.latitude;
    var long = position.coords.longitude;
}

I want to display the city name, it seems the only way to get it is to use a reverse geolocation API. I read Google's documentation for reverse geolocation but I don't know how to get the output on my site.

I don't know how to go use this: "http://maps.googleapis.com/maps/api/geocode/json?latlng='+lat+','+long+'&sensor=true" to display the city name on the page.

How can I achieve this?

Dingy answered 23/7, 2011 at 1:0 Comment(2)
If you are not going to use maps, you do KNOW that this is against Google's TOS right? Point 10.4 here developers.google.com/maps/terms No use of Content without a Google map. Unless the Maps APIs Documentation expressly permits you to do so, you will not use the Content in a Maps API Implementation without a corresponding Google map. For example, you may display Street View imagery without a corresponding Google map because the Maps APIs Documentation expressly permits this use.Neper
Yes, @Neper has a good point. There may be better services out there. I have worked with SmartyStreets before and I know they have much more open Terms of Service. Most services don't do reverse geocoding, however. I know Texas A&M has a free service but they have TOS warning that you can't collect data on other people, and they've had uptime and accuracy issues before.Spaceport
A
216

You would do something like that using Google API.

Please note you must include the google maps library for this to work. Google geocoder returns a lot of address components so you must make an educated guess as to which one will have the city.

"administrative_area_level_1" is usually what you are looking for but sometimes locality is the city you are after.

Anyhow - more details on google response types can be found here and here.

Below is the code that should do the trick:

<!DOCTYPE html> 
<html> 
<head> 
<meta name="viewport" content="initial-scale=1.0, user-scalable=no"/> 
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
<title>Reverse Geocoding</title> 

<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script> 
<script type="text/javascript"> 
  var geocoder;

  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(successFunction, errorFunction);
} 
//Get the latitude and the longitude;
function successFunction(position) {
    var lat = position.coords.latitude;
    var lng = position.coords.longitude;
    codeLatLng(lat, lng)
}

function errorFunction(){
    alert("Geocoder failed");
}

  function initialize() {
    geocoder = new google.maps.Geocoder();



  }

  function codeLatLng(lat, lng) {

    var latlng = new google.maps.LatLng(lat, lng);
    geocoder.geocode({'latLng': latlng}, function(results, status) {
      if (status == google.maps.GeocoderStatus.OK) {
      console.log(results)
        if (results[1]) {
         //formatted address
         alert(results[0].formatted_address)
        //find country name
             for (var i=0; i<results[0].address_components.length; i++) {
            for (var b=0;b<results[0].address_components[i].types.length;b++) {

            //there are different types that might hold a city admin_area_lvl_1 usually does in come cases looking for sublocality type will be more appropriate
                if (results[0].address_components[i].types[b] == "administrative_area_level_1") {
                    //this is the object you are looking for
                    city= results[0].address_components[i];
                    break;
                }
            }
        }
        //city data
        alert(city.short_name + " " + city.long_name)


        } else {
          alert("No results found");
        }
      } else {
        alert("Geocoder failed due to: " + status);
      }
    });
  }
</script> 
</head> 
<body onload="initialize()"> 

</body> 
</html> 
Awash answered 23/7, 2011 at 3:15 Comment(6)
Not true for admin area level 1, sometimes the city name is not there. - {"long_name"=>"San Francisco", "types"=>["administrative_area_level_2", "political"] , "short_name"=>"San Francisco"}, {"long_name"=>"California", "types"=>["administrative_area_level_1", "political"], "short_name"=>"CA" }, {"long_name"=>"United States", "types"=>["country", "political"], "short_name"=>"US"}Weismann
For V3, the {'latlng':latlng} string should be changed to 'location', as in ...geocode({'location':latlng}). This example got me almost there, but the 'latlng' string no longer seems to be valid in newer apis. See: developers.google.com/maps/documentation/javascript/… for specifics.Sices
@Awash how can we find only country name or country code instead of full address?Celisse
@Celisse in the if statement test for "country" and the city variable will now return country data. If re-name it country = results[0].address_components[i] you can access the data by country.long_name and country.short_nameAwash
Is there a way to narrow this down to cities within a province or just to check if location is from specific province, and if it is user gets redirected to a specific webpage?Swineherd
In the meantime you need an API key to use this google service. You'll get 200$ credits per month if registered.Arv
N
73

$.ajax({
  url: "https://geolocation-db.com/jsonp",
  jsonpCallback: "callback",
  dataType: "jsonp",
  success: function(location) {
    $('#country').html(location.country_name);
    $('#state').html(location.state);
    $('#city').html(location.city);
    $('#latitude').html(location.latitude);
    $('#longitude').html(location.longitude);
    $('#ip').html(location.IPv4);
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

<div>Country: <span id="country"></span></div>
  <div>State: <span id="state"></span></div>
    <div>City: <span id="city"></span></div>
      <div>Latitude: <span id="latitude"></span></div>
        <div>Longitude: <span id="longitude"></span></div>
          <div>IP: <span id="ip"></span></div>

Using html5 geolocation requires user permission. In case you don't want this, go for an external locator like https://geolocation-db.com IPv6 is supported. No restrictions and unlimited requests allowed.

Example

For a pure javascript example, without using jQuery, check out this answer.

Norry answered 18/12, 2015 at 15:7 Comment(4)
Thanks a lot for this treasure @OP. After spending 1 hour on SO this is the first link(geolocation-db.com) I found where the service supports unlimited free API hits per day.Bunn
this doesn't work with the lastest version angular (v12). The callback undefined error.Jagatai
Always it shows the United States, but my current location is Oman.Xylol
Does not return State or City only Country for me in AustraliaSexdecillion
C
60

Another approach to this is to use my service, http://ipinfo.io, which returns the city, region and country name based on the user's current IP address. Here's a simple example:

$.get("http://ipinfo.io", function(response) {
    console.log(response.city, response.country);
}, "jsonp");

Here's a more detailed JSFiddle example that also prints out the full response information, so you can see all of the available details: http://jsfiddle.net/zK5FN/2/

Conflagration answered 30/7, 2013 at 12:43 Comment(5)
Not as accurate though.Salable
Could not detect city and even trgion from IP of a big Russian provider : (Endocentric
Lol... this gives my internal network ip (192.168...)Tarahtaran
Can I do it from a device(handheld) browser?Phillip
Doesnt seem reliable. I am using a laptop and a mobile phone right now. The cities shown in both the devices through ipinfo.io are 530 kilometers apart!Nissy
G
18

You can get the name of the city, country, street name and other geodata using the Google Maps Geocoding API

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="https://code.jquery.com/jquery-2.2.3.js"></script>
</head>
<body>
    <script type="text/javascript">
        navigator.geolocation.getCurrentPosition(success, error);

        function success(position) {
            console.log(position.coords.latitude)
            console.log(position.coords.longitude)

            var GEOCODING = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + position.coords.latitude + '%2C' + position.coords.longitude + '&language=en';

            $.getJSON(GEOCODING).done(function(location) {
                console.log(location)
            })

        }

        function error(err) {
            console.log(err)
        }
    </script>
</body>
</html>

and to display this data on the page using jQuery

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="https://code.jquery.com/jquery-2.2.3.js"></script>
</head>
<body>

    <p>Country: <span id="country"></span></p>
    <p>State: <span id="state"></span></p>
    <p>City: <span id="city"></span></p>
    <p>Address: <span id="address"></span></p>

    <p>Latitude: <span id="latitude"></span></p>
    <p>Longitude: <span id="longitude"></span></p>

    <script type="text/javascript">
        navigator.geolocation.getCurrentPosition(success, error);

        function success(position) {

            var GEOCODING = 'https://maps.googleapis.com/maps/api/geocode/json?latlng=' + position.coords.latitude + '%2C' + position.coords.longitude + '&language=en';

            $.getJSON(GEOCODING).done(function(location) {
                $('#country').html(location.results[0].address_components[5].long_name);
                $('#state').html(location.results[0].address_components[4].long_name);
                $('#city').html(location.results[0].address_components[2].long_name);
                $('#address').html(location.results[0].formatted_address);
                $('#latitude').html(position.coords.latitude);
                $('#longitude').html(position.coords.longitude);
            })

        }

        function error(err) {
            console.log(err)
        }
    </script>
</body>
</html>
Grissel answered 29/4, 2016 at 4:12 Comment(0)
O
16

Here is updated working version for me which will get City/Town, It looks like some fields are modified in the json response. Referring previous answers for this questions. ( Thanks to Michal & one more reference : Link

var geocoder;

if (navigator.geolocation) {
  navigator.geolocation.getCurrentPosition(successFunction, errorFunction);
}
// Get the latitude and the longitude;
function successFunction(position) {
  var lat = position.coords.latitude;
  var lng = position.coords.longitude;
  codeLatLng(lat, lng);
}

function errorFunction() {
  alert("Geocoder failed");
}

function initialize() {
  geocoder = new google.maps.Geocoder();

}

function codeLatLng(lat, lng) {
  var latlng = new google.maps.LatLng(lat, lng);
  geocoder.geocode({latLng: latlng}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      if (results[1]) {
        var arrAddress = results;
        console.log(results);
        $.each(arrAddress, function(i, address_component) {
          if (address_component.types[0] == "locality") {
            console.log("City: " + address_component.address_components[0].long_name);
            itemLocality = address_component.address_components[0].long_name;
          }
        });
      } else {
        alert("No results found");
      }
    } else {
      alert("Geocoder failed due to: " + status);
    }
  });
}
Overeager answered 1/3, 2015 at 9:59 Comment(0)
G
11

geolocator.js can do that. (I'm the author).

Getting City Name (Limited Address)

geolocator.locateByIP(options, function (err, location) {
    console.log(location.address.city);
});

Getting Full Address Information

Example below will first try HTML5 Geolocation API to obtain the exact coordinates. If fails or rejected, it will fallback to Geo-IP look-up. Once it gets the coordinates, it will reverse-geocode the coordinates into an address.

var options = {
    enableHighAccuracy: true,
    fallbackToIP: true, // fallback to IP if Geolocation fails or rejected
    addressLookup: true
};
geolocator.locate(options, function (err, location) {
    console.log(location.address.city);
});

This uses Google APIs internally (for address lookup). So before this call, you should configure geolocator with your Google API key.

geolocator.config({
    language: "en",
    google: {
        version: "3",
        key: "YOUR-GOOGLE-API-KEY"
    }
});

Geolocator supports geo-location (via HTML5 or IP lookups), geocoding, address look-ups (reverse geocoding), distance & durations, timezone information and a lot more features...

Gigahertz answered 1/7, 2016 at 23:32 Comment(0)
P
10

After some searching and piecing together a couple of different solutions along with my own stuff, I came up with this function:

function parse_place(place)
{
    var location = [];

    for (var ac = 0; ac < place.address_components.length; ac++)
    {
        var component = place.address_components[ac];

        switch(component.types[0])
        {
            case 'locality':
                location['city'] = component.long_name;
                break;
            case 'administrative_area_level_1':
                location['state'] = component.long_name;
                break;
            case 'country':
                location['country'] = component.long_name;
                break;
        }
    };

    return location;
}
Perrotta answered 25/5, 2016 at 14:30 Comment(0)
T
5

You can use https://ip-api.io/ to get city Name. It supports IPv6.

As a bonus it allows to check whether ip address is a tor node, public proxy or spammer.

Javascript Code:

$(document).ready(function () {
        $('#btnGetIpDetail').click(function () {
            if ($('#txtIP').val() == '') {
                alert('IP address is reqired');
                return false;
            }
            $.getJSON("http://ip-api.io/json/" + $('#txtIP').val(),
                 function (result) {
                     alert('City Name: ' + result.city)
                     console.log(result);
                 });
        });
    });

HTML Code

<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<div>
    <input type="text" id="txtIP" />
    <button id="btnGetIpDetail">Get Location of IP</button>
</div>

JSON Output

{
    "ip": "64.30.228.118",
    "country_code": "US",
    "country_name": "United States",
    "region_code": "FL",
    "region_name": "Florida",
    "city": "Fort Lauderdale",
    "zip_code": "33309",
    "time_zone": "America/New_York",
    "latitude": 26.1882,
    "longitude": -80.1711,
    "metro_code": 528,
    "suspicious_factors": {
        "is_proxy": false,
        "is_tor_node": false,
        "is_spam": false,
        "is_suspicious": false
    }
}
Threemaster answered 29/7, 2017 at 13:58 Comment(0)
T
4

As @PirateApp mentioned in his comment, it's explicitly against Google's Maps API Licensing to use the Maps API as you intend.

You have a number of alternatives, including downloading a Geoip database and querying it locally or using a third party API service, such as my service ipdata.co.

ipdata gives you the geolocation, organisation, currency, timezone, calling code, flag and Tor Exit Node status data from any IPv4 or IPv6 address.

And is scalable with 10 global endpoints each able to handle >10,000 requests per second!

This answer uses a 'test' API Key that is very limited and only meant for testing a few calls. Signup for your own Free API Key and get up to 1500 requests daily for development.

$.get("https://api.ipdata.co?api-key=test", function(response) {
  $("#ip").html("IP: " + response.ip);
  $("#city").html(response.city + ", " + response.region);
  $("#response").html(JSON.stringify(response, null, 4));
}, "jsonp");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1><a href="https://ipdata.co">ipdata.co</a> - IP geolocation API</h1>

<div id="ip"></div>
<div id="city"></div>
<pre id="response"></pre>

The fiddle; https://jsfiddle.net/ipdata/6wtf0q4g/922/

Tetrad answered 5/9, 2017 at 20:5 Comment(0)
S
1

Here is another go at it .. Adding more to the accepted answer possibly more comprehensive .. of course switch -case will make it look for elegant.

function parseGeoLocationResults(result) {
    const parsedResult = {}
    const {address_components} = result;

    for (var i = 0; i < address_components.length; i++) {
        for (var b = 0; b < address_components[i].types.length; b++) {
            if (address_components[i].types[b] == "street_number") {
                //this is the object you are looking for
                parsedResult.street_number = address_components[i].long_name;
                break;
            }
            else if (address_components[i].types[b] == "route") {
                //this is the object you are looking for
                parsedResult.street_name = address_components[i].long_name;
                break;
            }
            else if (address_components[i].types[b] == "sublocality_level_1") {
                //this is the object you are looking for
                parsedResult.sublocality_level_1 = address_components[i].long_name;
                break;
            }
            else if (address_components[i].types[b] == "sublocality_level_2") {
                //this is the object you are looking for
                parsedResult.sublocality_level_2 = address_components[i].long_name;
                break;
            }
            else if (address_components[i].types[b] == "sublocality_level_3") {
                //this is the object you are looking for
                parsedResult.sublocality_level_3 = address_components[i].long_name;
                break;
            }
            else if (address_components[i].types[b] == "neighborhood") {
                //this is the object you are looking for
                parsedResult.neighborhood = address_components[i].long_name;
                break;
            }
            else if (address_components[i].types[b] == "locality") {
                //this is the object you are looking for
                parsedResult.city = address_components[i].long_name;
                break;
            }
            else if (address_components[i].types[b] == "administrative_area_level_1") {
                //this is the object you are looking for
                parsedResult.state = address_components[i].long_name;
                break;
            }

            else if (address_components[i].types[b] == "postal_code") {
                //this is the object you are looking for
                parsedResult.zip = address_components[i].long_name;
                break;
            }
            else if (address_components[i].types[b] == "country") {
                //this is the object you are looking for
                parsedResult.country = address_components[i].long_name;
                break;
            }
        }
    }
    return parsedResult;
}
Saree answered 24/5, 2017 at 18:13 Comment(0)
S
0

Here's an easy function you can use to get it. I used axios to make the API request, but you can use anything else.

async function getCountry(lat, long) {
  const { data: { results } } = await axios.get(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${long}&key=${GOOGLE_API_KEY}`);
  const { address_components } = results[0];

  for (let i = 0; i < address_components.length; i++) {
    const { types, long_name } = address_components[i];

    if (types.indexOf("country") !== -1) return long_name;
  }
}
Sudduth answered 19/6, 2020 at 7:57 Comment(0)
A
-3

Alternatively you could use my service, https://astroip.co, it is a new Geolocation API:

$.get("https://api.astroip.co/?api_key=1725e47c-1486-4369-aaff-463cc9764026", function(response) {
    console.log(response.geo.city, response.geo.country);
});

AstroIP provides geolocation data together with security datapoints like proxy, TOR nodes and crawlers detection. The API also returns currency, timezones, ASN and company data.

It is a pretty new api with an average response time of 40ms from multiple regions around the world, which positions it in the handful list of super fast Geolocation APIs available.

Big free plan of up to 30,000 requests per month for free is available.

Abert answered 5/12, 2020 at 18:4 Comment(2)
The service is not working (anymore?)Lionize
No, It's been shutdown months ago unfortunately.Abert

© 2022 - 2024 — McMap. All rights reserved.