Detecting the location of your users can be really useful if you want to personalize your their experience when they browse through your site. Want to show a uniquely tailored promotion? Want to change the language of your site or design based on where your users are visiting from?
These are some common use cases for detecting user location. It can also be to limit access to your website to remain compliant or if you simply do not yet serve certain locations. We will explore the various ways we can get your users’ location as well as their time zone (especially if you intend to send them emails or generate a lot of reports for them).
There are two very popular ways to detect a user’s location in the browser directly:
The Geolocation API allows you to ask the user to share their present location. You can argue that it is the most trusted method for detecting location, as the user will tell you themselves.
However, in a scenario where you want to format the content displayed to the user before it gets rendered, this isn’t exactly ideal. In addition, the Geolocation API may not work depending on the user’s browser permission settings.
To use the Geolocation API, you can do the following:
// Excerpt from https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API function geoFindMe() { if (!navigator.geolocation){ console.log("Geolocation is not supported by your browser"); return; } function success(position) { var latitude = position.coords.latitude; var longitude = position.coords.longitude; reverseGeocodingWithGoogle(latitude, longitude) } function error() { console.log("Unable to retrieve your location"); } navigator.geolocation.getCurrentPosition(success, error); }
It first checks that the browser has/supports the Geolocation API. If it does, it executes the rest of the code, which includes a success and error callback function. The navigator.geolocation.getCurrentPosition(success, error)
gives you the user’s exact coordinates, which you can put into Google Maps to get the exact user location.
You can send a request to Google’s reverse Geocoding API. It would require getting an API key:
function reverseGeocodingWithGoogle(latitude, longitude) { fetch(`https://maps.googleapis.com/maps/api/geocode/json? latlng=${latitude},${longitude}&key={GOOGLE_MAP_KEY}`) .then( res => res.json()) .then(response => { console.log("User's Location Info: ", response) }) .catch(status => { console.log('Request failed. Returned status of', status) }) }
The downside of using this method is that if the user does not allow you to get their location, you cannot detect their position accurately — or you may not even detect it at all. Also, it only works on secure servers (HTTPS). It is not supported on Internet Explorer ≤10 and OperaMini.
This is by far the most common way of detecting user location. Unlike the Geolocation API, it can only give you limited information like Country
and maybe City
, depending on the IP lookup provider you are using.
Here is a simple lookup:
fetch('https://extreme-ip-lookup.com/json/') .then( res => res.json()) .then(response => { console.log("Country: ", response.country); }) .catch((data, status) => { console.log('Request failed'); })
This works by making a request to the https://extreme-ip-lookup.com/json/
URL from the user’s browser so that their location is detected. This resource provides country, city, time zone, longitude, and latitude, among other things.
With a single query, you can tell which country a user is in and get their time zone. How convenient.
Many times, the information provided by IP lookup might be all you need. In that case, there would be no need to get the exact coordinates to pinpoint the user’s location in their city.
Here is a list of other places to check out when performing IP lookup:
N.B., understand that IP lookup mostly gives you accurate information about country and time zone of the originating request. The city may be the location of the ISP. If you intend to get the user’s exact city or region, you should use the Geolocation API and find ways to convince the user to share their location with you.
It is tempting to conclude that this is the easy part. Well, you could easily create a Date
object, send it to your server, and store that time. This comes with a lot of challenges, however, because you have to worry about doing internal calculations and not having them go off. This is why it is more important to fetch the user time zone above everything else.
As you saw above, we can detect time zone from IP address lookup. All you have to do is pick out the time zone from the response object along with the user location. Below, we will explore other ways of detecting time zone.
Moment.js includes a function that guesses the time zone of a user. It is quite accurate, provided you are using the most recent version.
Below is a quick example of how it works:
<div id="guess"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data-2012-2022.min.js"></script> <script> document.getElementById('guess').innerText = moment.tz.guess(); </script>
When you load the page, it shows you your current time zone. Create a index.html
file and open the file in a browser. Copy the above code into the file and save it. Then refresh the browser tab you just opened. Cool right?
MomentTz uses the built-in JavaScript Intl
object. It also has its data bank it checks the result of the Intl
object against to provide more accurate information. It also requires you to have included Moment.js before it can work.
Jstz is a simple lighter package for detecting time zone. I say lighter in comparison with Moment.js. It also makes use of the Intl API, so you can be confident of its results. To use the package, you can grab the CDN as follows:
<div id="guess"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.6/jstz.min.js"></script> <script> document.getElementById('guess').innerText = jstz.determine().name(); </script>
What you may notice from these libraries used for detecting time zone is that they do not require any network calls from your end. This means that if you intend only to pick user time zones, you may not need to do IP lookups — and that’s good because you’re paying for every call to the API, which can get expensive.
Intl
) itselfDon’t hate me, but let’s face it — if I showed you this, you may have ignored the rest of this article lol.
OK, so here is how to use it:
<div id="guess"></div> <script> document.getElementById('guess').innerText = Intl.DateTimeFormat().resolvedOptions().timeZone; </script>
Before you go “Wow!!!” understand that the packages highlighted above take a lot into consideration when detecting time zones. This makes them slightly more accurate than Intl
object alone. You may never notice the difference, but it feels good knowing someone’s got your back.
“Talk is cheap. Show me the code!” — or so the saying goes. Let’s do one better and build a really simple app that detects a user’s location and time zone information, and tell them what the time would be like in three other time zones around the world.
Here is what the simple application looks like:
Here is how we pieced the code together to achieve that. Place the following code in a file named index.html
:
<!-- index.html --> <!doctype html> <html class="no-js" lang=""> <head> <meta charset="utf-8"> <meta http-equiv="x-ua-compatible" content="ie=edge"> <title>Magic App</title> <meta name="description" content="Magic App"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="index.css"> </head> <body> <h1>Magic App Here</h1> <div id="main"> <div id="time" class="sub"> <div> <h2>Your local time</h2> <span class="local"></span> </div> <div> <h2>Magic App Server Time</h2> <span class="server"></span> </div> </div> <div id="location" class="sub"> <h2>And you are in...</h2> <div class="address"></div> </div> </div> <!-- Script here --> </body> </html>
index.css file and add the following:
/*index.css*/ h1 { text-align: center } #main { max-width: 900px; display: table; margin-left: 30vw; margin-top: 10vh; } #main .sub { display: block; float: left; min-width: 300px; min-height: 300px; border: 0.5px solid #bbb; border-radius: 4px; padding: 15px; } #main .sub h2{ font-size: 20px; } #main #time { margin-right: 5vw; } #main #time div { display: block; min-height: 120px; }
This may be the most simple application you have ever seen. We’re not doing anything fancy, just going straight to the point. Standard HTML and CSS — that’s all.
Now, let’s add the JavaScript that brings all of these to life: add the following to index.html
:
[...] <script src="https://cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.6/jstz.min.js"></script> <script> document.addEventListener("DOMContentLoaded", function(event) { // The main sauce here }); </script> [...]
We have laid the foundation for what is to come. The first thing we want to do is detect whether the user’s browser supports the Geolocation API:
[...] document.addEventListener("DOMContentLoaded", function(event) { if (!navigator.geolocation){ console.log("Geolocation is not supported by your browser"); ipLookup(); } else { navigator.geolocation.getCurrentPosition(success, error); } // More sauce here }); [...]
Now, we get to execute our code if the Geolocation API is available/accessible. If it is not, we just fall back to IP lookup, like we saw above.
Let’s create the success
, error
, and ipLookup
methods:
[...] document.addEventListener("DOMContentLoaded", function(event) { [...] function success(position) { var latitude = position.coords.latitude; var longitude = position.coords.longitude; reverseGeocodingWithGoogle(latitude, longitude) } function error() { console.log("Unable to retrieve your location"); } function ipLookup() { fetch('https://extreme-ip-lookup.com/json/') .then( res => res.json()) .then(response => { fallbackProcess(response) }) .catch((data, status) => { console.log('We could not find your location'); }) } // More sauce here }); [...]
We have already seen how these work above, so I’m going to skip explaining each. Let’s add the reverseGeocodingWithGoogle
method now:
[...] document.addEventListener("DOMContentLoaded", function(event) { [...] function reverseGeocodingWithGoogle(latitude, longitude) { fetch(`https://maps.googleapis.com/maps/api/geocode/json? latlng=${latitude},${longitude}&key={GOOGLE_MAP_KEY}`) .then( res => res.json()) .then(response => { processUserData(response) }) .catch(status => { ipLookup() }) } // Even more sauce here }); [...]
You may have noticed that I introduced two new functions, processUserData
and fallbackProcess
. These are just to keep things clean and reusable. Let’s now add the both of them:
[...] document.addEventListener("DOMContentLoaded", function(event) { [...] function processUserData(response) { var address = document.querySelector('.address') address.innerText = response.results[0].formatted_address } function fallbackProcess(response) { var address = document.querySelector('.address') address.innerText = `${response.city}, ${response.country}` } // timezone sauce here }); [...]
You see the methods just perform assignments — nothing too complex. For the address
variable, I should ordinarily define it in the global scope, but I brought it into the function so you would not miss it. Do note that this is not the best way to reuse code.
Now, let’s detect time zone:
[...] document.addEventListener("DOMContentLoaded", function(event) { [...] var localTime = jstz.determine().name(); var serverTime = "Asia/Novosibirsk"; document.querySelector('.server').innerText = new Date().toLocaleString("en-US", {timeZone: serverTime}); document.querySelector('.local').innerText = new Date().toLocaleString("en-US", {timeZone: localTime}); }); [...]
And that completes our magic app. You can check out the working app on Codepen below:
See the Pen
Detect Timezone and Location in JavaScript by Chris Nwamba (@codebeast)
on CodePen.
I hope this article has been useful to you. I hope it helps you improve your user experience and to build a more internationalized application with JavaScript.
One last thing that can come in handy would be to get a DateTime string in a particular time zone using JavaScript. Not to worry, I got you. Here is the simple line of code you need:
new Date().toLocaleString("en-US", {timeZone: "TIMEZONE_STRING_HERE"})
Share your experiences using these tools, let’s all learn together.
Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.
LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to see exactly what the user did that led to an error.
LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
5 Replies to "Detect location and local time zone of users in JavaScript"
thank you for the post! Just realised that you mixed up longitude and latitude in the reverseGeocodingWithGoogle function 😉
I am glad that i found you. I think u don’t mind if i use ur code?
Thanks for sharing useful code/script to locate any IP address by using this step.
Interesting post! I have one query related to DST. Is there any way in Javascript which will give us user’s tzid and tz long name based on tz database used in Joda library? These tzids are widely used universally and are defined by IANA database. Java’s Joda Library also use the same tz database.
Joda library gives different DST data (not shown below) for same offset i.e. +04:00…like as below:
(+04:00) Europe/Ulyanovsk, Greenwich Mean Time
(+04:00) Europe/Volgograd, Moscow Standard Time
(+04:00) Indian/Mahe, Seychelles Time
(+04:00) Indian/Mauritius, Mauritius Time
(+04:00) Indian/Reunion, Reunion Time
we have to apply those DST rules while sending icalendar file (ICS files) to users. Users are located at different regions.
if user’s timezone detected by JS is “+04:00 with some country”, then how can we decide which DST rule out of several should be applied? Because I dont have any country to region mapping.
i didn’t see the place am in?