Table of Contents
- What is IP or Geolocation?
- Getting the User’s Location
- Getting user’s latitude and longitude information by using Geolocation API
- Enhancing Location-Based Services with Reverse Geocoding
- Here is the full code:
- Getting the User’s IP address
- Best Practices for Collecting and Handling User Location Data
- Conclusion
Web applications are becoming more and more personalized. Also, there is a rise of web applications that use location-based services for multiple reasons. It can be either for privacy, security or any specific location-based features.
What is IP or Geolocation?
First, let’s understand what is an IP or IP address.
Each device that uses an internet has a unique address just like every house has a unique number or address. This unique address of the device is called IP address. It helps devices to communicate with each other over the internet.
Here, the IP stands for “Internet Protocol” which is a set of rules that devices use to communicate with each other over the Internet. Now let’s understand Geolocation.
The Geolocation is combination of two words. First is “Geo” which means the earth and the second word is “location” which means where something is located on earth.
So, the “IP-Geolocation” is a way to find where the device is located physically based on its IP address. The accuracy of IP-Geolocation data depends on different factors such as which method is used to get the data, the quality of the data, the type of device etc. The data can be less accurate for mobile devices since these devices frequently change networks. Now let’s see how we can get the use.
Getting the User’s Location
npm create vite@latest your-app-name
Once you execute the above command it will show you a list of frameworks, now select React from the list using arrow keys and press enter.
- Now it will show you a list of variants, select Javascript from those variants. Then it will create a folder with your app name and add all the necessary files. Now use the following commands to install all the required libraries and run the development server.
cd your-app-name
This command will change the current directory to the app directorynpm install
Using this command we will install all the required librariesnpm run dev
This command will start the development server probably at localhost:5173
Now the development server is up and running so let’s get the user’s IP address.
Getting user’s latitude and longitude information by using Geolocation API
This Geolocation API is accessed via a call to navigator.geolocation
which is a property that can return a Geolocation object. Let’s see what is navigator.
- navigator: It is an interface that represents the state and the identity of the user agent (browser). Let’s log this navigator and see what other properties it provides.
Open the App.jsx
file and clean all the code inside the return statement and just keep the parent div
with the class App
then use the console.log(navigator)
inside a useEffect
as given in the following code.
import { useEffect } from "react";
import "./App.css";
function App() {
useEffect(() => {
console.log(navigator);
}, []);
return <div className="App"></div>;
}
export default App;
In your development server tab open the console by pressing F12 or with the right click of the mouse. You will see the list of different properties such as appCodeName, Bluetooth, clipboard, geolocation etc. Let’s log the geolocation. Just add the geolocation in the log like this console.log(navigator.geolocation)
. In the console you will see an empty object because we don’t have permission to access the geolocation for now so let’s see how to get this permission. Check out the following code and the explanation.
useEffect(() => {
if (navigator.geolocation) {
navigator.permissions
.query({ name: "geolocation" })
.then(function (result) {
console.log(result);
});
} else {
console.log("Geolocation is not supported by this browser.");
}
}, []);
In the above useEffect
, first we will check if there is navigator. geolocation or not and if it’s true we will check the permissions.
- navigator.permissions: It returns a Permissions object that can be used to query and update the permission status.
- query: It is a method of Permission which returns the state of a user permission. It takes an object that has comma separated list of name-value pairs. Here we have passed geolocation since we want to know the status of geolocation permission.
Here we are getting a Promise that is why we will use then
keyword and log the results. If you check the console of the browser you will see the following object.
{
name: "geolocation",
onchange: null,
state: "prompt"
}
The state can have 3 different values,
- granted: That means we have permission to access location so we can call the geolocation directly.
- prompt: The user will get a popup asking for permission.
- denied: That means the user has denied sharing his location.
For the “granted” and “prompt” states we can create a function to get the current position of the user but for the “denied “state, we can show instructions how they can enable location permission in their browser.
NOTE: There is no way you can prompt for location permission again if the user has already denied the location permission unless the user enables it manually in his browser.
Let’s use 3 conditions for all 3 permission states as the following,
useEffect(() => {
if (navigator.geolocation) {
navigator.permissions
.query({ name: "geolocation" })
.then(function (result) {
console.log(result);
if (result.state === "granted") {
//If granted then you can directly call your function here
} else if (result.state === "prompt") {
//If prompt then the user will be asked to give permission
} else if (result.state === "denied") {
//If denied then you have to show instructions to enable location
}
});
} else {
console.log("Geolocation is not supported by this browser.");
}
}, []);
In the prompt state let’s use the function called getCurrentPosition
. This function takes the following arguments.
- success: A callback function that will be called if the location is successfully retrieved.
- error: A callback function that will be called if there is an error retrieving the location. This is optional.
-
options: The options take different parameters such as maximumAge, timeout, enableHighAccuracy etc. You can read more about these options from MDN documentation. This is also optional.
Let’s implement all 3 arguments. First let’s create a success function. Before the useEffect
add the following success function.
function success(pos) {
var crd = pos.coords;
console.log("Your current position is:");
console.log(`Latitude : ${crd.latitude}`);
console.log(`Longitude: ${crd.longitude}`);
console.log(`More or less ${crd.accuracy} meters.`);
}
This callback function will return a position object that has coords which means coordinates. You can get values such as latitude, longitude, accuracy etc from coordinates. Now add the following error function after the success function.
function errors(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
}
Let’s declare an option object as well,
var options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0,
};
Now paste the following line in the “prompt” and “granted” conditions and check the output in your browser.
navigator.geolocation.getCurrentPosition(success, errors, options);
You can see one prompt in the browser asking you for location permission. Once you give the permission you can see coordinate values in the console tab. Here is the full code.
import { useEffect } from "react";
import "./App.css";
function App() {
var options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0,
};
function success(pos) {
var crd = pos.coords;
console.log("Your current position is:");
console.log(`Latitude : ${crd.latitude}`);
console.log(`Longitude: ${crd.longitude}`);
console.log(`More or less ${crd.accuracy} meters.`);
}
function errors(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
}
useEffect(() => {
if (navigator.geolocation) {
navigator.permissions
.query({ name: "geolocation" })
.then(function (result) {
console.log(result);
if (result.state === "granted") {
//If granted then you can directly call your function here
navigator.geolocation.getCurrentPosition(success, errors, options);
} else if (result.state === "prompt") {
//If prompt then the user will be asked to give permission
navigator.geolocation.getCurrentPosition(success, errors, options);
} else if (result.state === "denied") {
//If denied then you have to show instructions to enable location
}
});
} else {
console.log("Geolocation is not supported by this browser.");
}
}, []);
return <div className="App"></div>;
}
export default App;
Enhancing Location-Based Services with Reverse Geocoding
const [location, setLocation] = useState();
function getLocationInfo(latitude, longitude) {
const url = `https://api.opencagedata.com/geocode/v1/json?q=${latitude},${longitude}&key=${APIkey}`;
fetch(url)
.then((response) => response.json())
.then((data) => {
console.log(data);
if (data.status.code === 200) {
console.log("results:", data.results);
setLocation(data.results[0].formatted);
} else {
console.log("Reverse geolocation request failed.");
}
})
.catch((error) => console.error(error));
}
getLocationInfo
function takes latitude and longitude then it uses the URL from the opencage’s documentation which takes latitude, longitude and the API key. In this function we have used fetch to get the data from the URL and if the status code is 200 then we will store the data in the location state. You can check your console on the browser to see which type of data you are getting. For now, we are using the value from the formatted
property. To get more info about the response object you can check the documentation. Now let’s call this function from the success function that we have already defined. function success(pos) {
var crd = pos.coords;
...
...
getLocationInfo(crd.latitude, crd.longitude);
}
Now, whenever the user agrees to give his location the success function will run and also it will pass the latitude and longitude info to the getLocationInfo function and execute it. You can use this location state to display the location in your web app.
Here is the full code:
import { useEffect, useState } from "react";
import "./App.css";
const APIkey = "Enter-your-api-key";
function App() {
const [location, setLocation] = useState();
function getLocationInfo(latitude, longitude) {
const url = `https://api.opencagedata.com/geocode/v1/json?q=${latitude},${longitude}&key=${APIkey}`;
fetch(url)
.then((response) => response.json())
.then((data) => {
console.log(data);
if (data.status.code === 200) {
console.log("results:", data.results);
setLocation(data.results[0].formatted);
} else {
console.log("Reverse geolocation request failed.");
}
})
.catch((error) => console.error(error));
}
var options = {
enableHighAccuracy: true,
timeout: 5000,
maximumAge: 0,
};
function success(pos) {
var crd = pos.coords;
console.log("Your current position is:");
console.log(`Latitude : ${crd.latitude}`);
console.log(`Longitude: ${crd.longitude}`);
console.log(`More or less ${crd.accuracy} meters.`);
getLocationInfo(crd.latitude, crd.longitude);
}
function errors(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
}
useEffect(() => {
if (navigator.geolocation) {
navigator.permissions
.query({ name: "geolocation" })
.then(function (result) {
console.log(result);
if (result.state === "granted") {
//If granted then you can directly call your function here
navigator.geolocation.getCurrentPosition(success, errors, options);
} else if (result.state === "prompt") {
//If prompt then the user will be asked to give permission
navigator.geolocation.getCurrentPosition(success, errors, options);
} else if (result.state === "denied") {
//If denied then you have to show instructions to enable location
}
});
} else {
console.log("Geolocation is not supported by this browser.");
}
}, []);
return (
<div className="App">
{location ? <>Your location: {location}</> : null}
</div>
);
}
export default App;
You can implement an error state as well which display the error message when the API or function can not fetch the data properly. Also implement the required error handling method on the functions as well. This is how you can get a lot of information about the device’s location. Now let’s see how you can get the device’s IP address.
Getting the User’s IP address
const [ipAddress, setIpAddress] = useState("");
useEffect(() => {
const fetchIp = async () => {
try {
const response = await fetch("https://api.ipify.org?format=json");
const data = await response.json();
setIpAddress(data.ip);
} catch (error) {
console.error(error);
}
};
fetchIp();
}, []);
In the above code, we have created one state called ipAddress
to store the IP address. The ipfy is a public API so we don’t need any API key and we can directly use the URL. In useEffect
we have created one async function called fetchIp
which will fetch and store the IP address in the ipAddress
state. Don’t forget to call the fetchIp
function in the useEffect
.
This is how you can easily get the device’s IP address. There are multiple APIs that provide such services. For the server side, you can generally obtain the IP address from the request that the user sent you to get the webpage or any data. However, you should not rely solely on the IP address since some ISPs use shared IP addresses, which means multiple users may have the same IP address. Additionally, some users use VPNs and proxies as well.
Best Practices for Collecting and Handling User Location Data
When it comes to the user’s data it is always a crucial part in any application. As a developer, it is our job to create an application that is user-centric and protects users’ data. For the data like the device’s location developer can face many problems such as,
- How accurate is the IP or Geolocation data?
- What to do when the user does not give consent to use its location?
- How to handle and protect the data securely?
Implementing location-based features can be challenging, but by following the best practices you can provide users more personalized and secure experience. Keep the following points in mind when handling location based data.
-
Accuracy: When using the IP address you should double check it by using more than one api and cross-check the location. You must include a fallback mechanism in location based services and features. It is better to verify the data since location data can be affected by factors such device settings, network connections etc.
-
Privacy: This is the major concern when collecting any user’s data since you have to keep in check with the different laws of multiple countries. Developers should always respect the user’s privacy. It is necessary to have a clear and concise privacy policy when it comes to collecting any data from the user. You must tell the user whenever you are collecting any sensitive information. If there are any location based features then you should clearly show why and how you are going to use the data. Also, you should provide an opt-out option for the user so if they don’t want to share their data they can opt out easily.
-
Security: For the security of the data you can implement authentication mechanisms like OAuth or JWT and secure the API endpoints from any unauthorised access. You should always suggest user to use strong passwords, updating browsers etc. You must encrypt the data using HTTPS and SSL certificates to ensure secure communication between the client and the server. In the backend, you can implement role-based access control so that only selected user such as only admins can access the data. Before updating any dependency you should always check if it is from the official source or not.