Unlocking Real-Time User Location Verification with Geolocation and Google Maps API: A JavaScript Journey

Unlocking Real-Time User Location Verification with Geolocation and Google Maps API: A JavaScript Journey

Introduction:

In today's digital world, verifying a user's location has become an essential aspect of many applications and services. Whether it's for ensuring security, personalizing user experiences, or tailoring content based on geographic location, real-time location verification is a powerful tool. In this blog post, we will explore how to leverage the Geolocation and Google Maps API in JavaScript to achieve this goal seamlessly.

Problem: Verify the user's real-time location corresponding to a specific location.

We already have coordinates for a specific location, we want to verify whether our user is present at this location or not. We will leverage the user's real-time location to be present within a surrounding area of that given coordinates.

I hope the problem is clear to you. Now, let's discuss the solution to this problem.

1. Understanding Geolocation API:

The Geolocation API provides a simple way to retrieve the user's current location.

Let's start by requesting permission to access the geolocation data and retrieving the latitude and longitude coordinates.

// Request permission to access geolocation data
navigator.geolocation.getCurrentPosition(
  (position) => {
    const latitude = position.coords.latitude;
    const longitude = position.coords.longitude;
    console.log(`Latitude: ${latitude}, Longitude: ${longitude}`);
    // Further processing of location data
  },
  (error) => {
    console.error(`Error retrieving location: ${error.message}`);
  }
);

The code above demonstrates how to use the Geolocation API to retrieve the user's current location.

  • The navigator.geolocation.getCurrentPosition() function is called to initiate the process of retrieving the position.

  • It takes two callback functions as arguments. The first function is executed when the position is successfully retrieved, while the second function is called if there is an error.

  • In the success callback function, the position object contains the latitude and longitude coordinates, accessible through position.coords.latitude and position.coords.longitude, position.coords.altitude respectively.

  • We will use the latitude and longitude to perform further processing with the location data as per our requirements.

  • In case of an error, the error callback function is executed, and the specific error message is logged to the console.

By using this code, you can access the user's geolocation data and perform tasks such as displaying their location on a map, calculating distance, or implementing location-based features in your application.

Remember to handle user permissions appropriately and provide clear explanations for accessing their location data to ensure a smooth user experience.

2. Correlating Geo Coordinates with User Location:

Now that we have obtained the latitude and longitude coordinates, we can leverage the Google Maps API to retrieve detailed location information. By requesting the Reverse Geocoding API, we can obtain the name of the sub-locality, city, country, and other relevant details corresponding to the provided coordinates.

Here's an example of how to make a request to the Geocoding API using the latitude and longitude coordinates:

// will provide lat,long from above geolocation function 
const latitude = 27.1766701; 
const longitude = 78.0080745;
const apiKey = 'YOUR_API_KEY';

const url = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${apiKey}`;

fetch(url)
  .then(response => response.json())
  .then(data => {
    // Process the geocoding data
    const required_data = data.results;
    console.log(`API Response: ${required_data}`);
    // Further processing of location information
  })
  .catch(error => {
    console.error(`Error retrieving location information: ${error}`);
  });

In the code snippet above, we construct the URL for the Reverse Geocoding API request by providing the latitude, longitude, and your API_KEY.

  • The fetch() function is used to make an HTTP request to the Geocoding API URL.

  • Upon receiving the response, we parse the data as JSON using the .json() method.

  • We can then access various properties of the response from data.results, to extract the sub-localities corresponding to the provided coordinates.

Make sure to replace 'YOUR_API_KEY' in the URL with your actual Google Maps API key to authenticate the request. Know how to generate an API key.

Note: Ensure that you adhere to the terms of use and any usage limits imposed by the Google Maps API when incorporating this functionality into your application. Especially always consider pricing. 💰🙉

Now let's connect the dots and build a proper solution for our application.

/*  
    Get given coords from your DB, currenty using dummy coordinates of 
    Mahavir Enclave Part 1, Mahavir Enclave, New Delhi, Delhi.
*/

const specific_given_coords = {
  latitude: 28.596618,
  longitude: 77.078771,
};

const API_KEY = "YOUR_API_KEY";

// call this function wherever you want use
checkLocation();

async function checkLocation() {
  try {
    const usersCoords = await getUserLocation();
    const isUserPresent = await verifyLocation(usersCoords);

    console.log(isUserPresent); // 🫰 your output

    return isUserPresent;
  } catch (e) {
    // show this error to user to check device location permission
    console.log(e);
  }
}

// get user's current location
function getUserLocation() {
  return new Promise((resolve, reject) => {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        const latitude = position.coords.latitude;
        const longitude = position.coords.longitude;
        resolve({ latitude, longitude });
      },
      (error) => {
        console.error(`Error retrieving location: ${error.message}`);
        reject(new Error("Location not available"));
      }
    );
  });
}

// verify user's location corresponding to given coordinates
async function verifyLocation(usersCoords) {
  const { latitude, longitude } = specific_given_coords;
  const { latitude: userLat, longitude: userLong } = usersCoords;
  try {
    const givenCoordsLocalities = await fetchGeoCoordsData(latitude, longitude);
    const userCurrentLocalities = await fetchGeoCoordsData(userLat, userLong);

    // if any locality matches in both arrays, it means user is nearby given coordinates 🎉
    const matchedLocalities = findIntersection(
      givenCoordsLocalities,
      userCurrentLocalities
    );

    return Boolean(matchedLocalities.length);
  } catch (e) {
    console.log(e);
  }
}

// make google api request to get revese geocoding results
function fetchGeoCoordsData(latitude, longitude) {
  const url = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&key=${API_KEY}`;

return new Promise((resolve, reject) => {
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        const required_data = data.results;
        const localites = getLocalities(required_data);
        resolve(localites);
      })
      .catch((error) => {
        console.error(`Error retrieving location information: ${error}`);
        reject(new Error("Error in Google Api"));
      });
  });
}

// get only sublocalities names from google response
function getLocalities(googleResponse) {
  // console googleResponse to check the response format
  const localities = [];

  googleResponse.forEach((resp) => {
    const address = resp.address_components;
    address.forEach((addResp) => {
      if (addResp.types.includes("sublocality")) {
        localities.push(addResp.long_name);
      }
    });
  });

  // storing unique names of sublocalities in an array
  // using only sublocalities is a catch😎 to find out nearby location
  return Array.from(new Set(localities));
}

// check if any locality matches in both array
function findIntersection(arr1, arr2) {
  console.log(arr1, arr2);
  return arr1.filter((value) => arr2.includes(value));
}

Let me walk you through the above code quickly:-

  1. The specific_given_coords object stores the latitude and longitude coordinates of a specific location.

  2. API_KEY holds your Google Maps API key.

  3. The checkLocation() function is called to initiate the process and get output.

  4. getUserLocation() retrieves the user's current location using the Geolocation API.

  5. verifyLocation() compares the user's location with the given coordinates to determine if they are nearby.

  6. fetchGeoCoordsData() makes an API request to the Google Maps Geocoding API to obtain the location details for the provided coordinates.

  7. getLocalities() extracts the sublocality names from the Google API response.

  8. findIntersection() finds the common sub-localities between the given coordinates and the user's current location.

  9. The result is logged to the console and returned as a boolean indicating if there is a match.

Overall, the code retrieves the user's location, fetches the corresponding location details, and compares them with the given coordinates to determine if the user is nearby.

For a better understanding of the above code, you need knowledge of basic javascript features like Promise, async, await and ES6.

Check out Youtube to learn the basics of javascript.

I hope now you are clear with the above code. Hurray🎉, we got what we wanted.

Check out the below code sandbox for a live demonstration, remember to add your api_key.

To further check for a valid scenario. Add 28.5977408, 77.0569059 latitude and longitude in the Chrome Dev tool's Location Sensors.

Follow these steps to set up a custom location using Chrome's Dev tools.

The next step is to choose the Other option in the Location dropdown under the Sensors tab. Add your custom coordinates here.

Boom🥳, You are now at a custom location. Reload the page and check the output.

Extra Tip: Cost optimization by not calling Google API again.

Now, we've understood how to initially verify user's current location corresponds to the given coordinates. So, we do not need to make a Google API call again to reverify the same thing(same sublocality) if the user is even moving a little from its starting position.

The above diagram indicates that initially, we will verify the user's current location and save these starting coordinates and allow the user to move a certain distance from this particular point.

Let's leverage the user to move 100m from its starting verified position. Calculate the straight distance b/w starting verified coordinates and the user's current location(new coordinates).

Calculate the distance b/w two coordinates.

const ALLOWED_RADIUS = 0.1; // 100 M

// Convert from degrees to radians
function degreesToRadians(degrees) {
  var radians = (degrees * Math.PI) / 180;
  return radians;
}

// check user's new position is within radius of starting coords
function isWithinRadius(startCoords, distanceAway = ALLOWED_RADIUS) {
  return new Promise(async (resolve, reject) => {
    try {
      const currentPos = await getUserLocation(); // mentioned above
      let startingLat = degreesToRadians(startCoords.latitude);
      let startingLong = degreesToRadians(startCoords.longitude);
      let destinationLat = degreesToRadians(currentPos.latitude);
      let destinationLong = degreesToRadians(currentPos.longitude);

      // Radius of the Earth in kilometers
      let radius = 6571;

      // Haversine equation
      let distanceInKilometers =
        Math.acos(
          Math.sin(startingLat) * Math.sin(destinationLat) +
            Math.cos(startingLat) *
              Math.cos(destinationLat) *
              Math.cos(startingLong - destinationLong)
        ) * radius;
      if (distanceInKilometers <= distanceAway) {
        // 100 M away or not
        return resolve(true);
      }
      const error = new Error("Away from location");
      error.status = 400;
      reject(error);
    } catch (e) {
      reject(e);
    }
  });
}

You can understand about above function here

  1. Save usersCoords from the initial implementation and pass it as an argument in isWithinRadius(usersCoords) . it is our initial point we will check the user's new position from this point.

  2. The above code can help us to verify the user's new position locally without making any Google API call. It will save us money of course.🤩

That's it. We've covered everything required to verify user's real-time location corresponds to a given coordinate.

Final words:

Use this code to build your applications. I hope this blog has helped to understand to build this feature. Keep learning 😇. Comment your thoughts or suggestions. Please check my videos on Youtube and subscribe to the channel. Follow me on Linkedin for more updates.

Did you find this article valuable?

Support Utkarsh Gupta- Special by becoming a sponsor. Any amount is appreciated!