The Geolocation API lets a website request your current location — but only if you allow it.
❓ Why Use the Geolocation API?
Many web apps rely on user location, such as:
Search engines
eCommerce websites
Maps and navigation apps
Weather apps
Example:
An online store may ask for your location to show nearby product availability or location-based discounts.
Another example:
If you’re in San Francisco and search “pizza”, Google shows pizza places near you.
🔰 Geolocation Object
The API is accessed through:
navigator.geolocation✅ Check Browser Support
Before using it, check if the browser supports geolocation:
if (!navigator.geolocation) {
console.error("Your browser doesn't support Geolocation");
}🚩 Get the Current Position
To get a user’s location, call:
navigator.geolocation.getCurrentPosition(successCallback, errorCallback);What happens:
The browser requests permission from the user.
If permission is granted, the API uses GPS or network data to find the latest location.
The request is asynchronous (it takes time).
On success:
You receive a GeolocationCoordinates object containing:
latitudelongitude
📌 Geolocation example
The following example shows a simple application that has one button. When you click the button, the browser will request you to share your location. If you agree, it’ll show your current latitude and longitude.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript Geolocation Demo</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="container">
<button id="show" class="btn">Show my location</button>
<div id="message"></div>
</div>
<script src="js/app.js"></script>
</body>
</html>* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #f0f4f8, #d9e4f5);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.container {
background-color: #ffffff;
padding: 2rem 3rem;
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
text-align: center;
max-width: 400px;
width: 100%;
}
.btn {
padding: 0.75rem 1.5rem;
background-color: #007bff;
border: none;
border-radius: 8px;
color: white;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.3s ease;
margin-bottom: 1rem;
}
.btn:hover {
background-color: #0056b3;
}
#message {
font-size: 1rem;
padding: 0.5rem;
border-radius: 6px;
margin-top: 0.5rem;
transition: all 0.3s ease;
}
.success {
color: #155724;
background-color: #d4edda;
border: 1px solid #c3e6cb;
}
.error {
color: #721c24;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
}(() => {
const message = document.querySelector('#message');
// check if the Geolocation API is supported
if (!navigator.geolocation) {
message.textContent = `Your browser doesn't support Geolocation`;
message.classList.add('error');
return;
}
// handle click event
const btn = document.querySelector('#show');
btn.addEventListener('click', function () {
// get the current position
navigator.geolocation.getCurrentPosition(onSuccess, onError);
});
// handle success case
function onSuccess(position) {
const {
latitude,
longitude
} = position.coords;
message.classList.add('success');
message.textContent = `Your location: (${latitude},${longitude})`;
}
// handle error case
function onError() {
message.classList.add('error');
message.textContent = `Failed to get your location!`;
}
})();How it works :
First, select the
#messageelement by using thequerySelector()method.Next, show an error message if the browser doesn’t support the Geolocation API.
Then, select the button and attach a click event handler. The click event handler calls the
getCurrentPosition()method of thenavigator.geolocationobject to get the current position of the user.The
onSuccessandonErrorcallback functions are for handling the success and error cases.After that, define the
onSuccess()function that gets the latitude and longitude from theposition.coordsand shows them on the<div>element with idmessage.Finally, define the
onError()function that shows an error message in case thegetCurrentPosition()method fails.
When you click the Show my location button, the browser will request you to share your location like this.
If you click the Allow button, you’ll see your location as shown in the following picture :
This time if you click the Never allow button.
The app will show an error message :
<div class="infographic-geolocation">
<style>
.infographic-geolocation {
--ink: #1a1a1a;
--ink-soft: #5c5c5c;
--paper: #ffffff;
--paper-alt: #f0ece4;
--accent: #2563eb;
--accent-soft:#e3ebfd;
--line: #ddd6c9;
--demo-btn: #007bff;
--demo-btn-hover: #0056b3;
--demo-success-fg: #155724;
--demo-success-bg: #d4edda;
--demo-success-bd: #c3e6cb;
--demo-error-fg: #721c24;
--demo-error-bg: #f8d7da;
--demo-error-bd: #f5c6cb;
--mono-font: 'IBM Plex Mono', monospace;
--display-font: 'Fraunces', Georgia, serif;
box-sizing: border-box;
max-width: 880px;
margin: 0 auto;
font-family: 'Inter', system-ui, sans-serif;
color: var(--ink);
background: var(--paper);
overflow-x: hidden;
}
.infographic-geolocation[data-theme="dark"] {
--ink: #e8e6e1;
--ink-soft: #9a968c;
--paper: #121212;
--paper-alt: #1e1e26;
--accent: #5b8def;
--accent-soft:#202942;
--line: #2c313d;
}
.infographic-geolocation * { box-sizing: border-box; }
.infographic-geolocation h1 { font-family: var(--display-font); font-weight: 600; margin: 0; }
.infographic-geolocation p { margin: 0; }
.infographic-geolocation button { font-family: inherit; }
.geo-icon { width: 1em; height: 1em; display: inline-block; vertical-align: -0.15em; }
.geo-icon svg { width: 100%; height: 100%; display: block; }
.geo-wrap { padding: clamp(1.25rem, 5vw, 2.5rem) clamp(1.1rem, 5vw, 3rem) 2rem; }
.geo-hero { text-align: center; margin-bottom: 1.3rem; }
.geo-hero h1 { font-size: clamp(1.35rem, 4.5vw, 1.85rem); }
.geo-hero p { color: var(--ink-soft); margin-top: 0.4rem; font-size: 0.86rem; }
/* --- live demo card (matches the source page's own styling) --- */
.geo-card { max-width: 340px; margin: 0 auto 1rem; background: #fff; border-radius: 12px; padding: 1.6rem 1.4rem;
box-shadow: 0 10px 25px rgba(0,0,0,0.1); text-align: center; }
.infographic-geolocation[data-theme="dark"] .geo-card { background: #1a1a1a; box-shadow: 0 10px 25px rgba(0,0,0,0.4); }
.geo-btn { padding: 0.7rem 1.4rem; background-color: var(--demo-btn); border: none; border-radius: 8px; color: #fff;
font-size: 0.9rem; cursor: pointer; transition: background-color 0.2s ease; margin-bottom: 0.8rem; display: inline-flex;
align-items: center; gap: 0.4rem; }
.geo-btn:hover { background-color: var(--demo-btn-hover); }
.geo-btn .geo-icon { width: 15px; height: 15px; }
.geo-message { font-size: 0.85rem; padding: 0.5rem; border-radius: 6px; margin-top: 0.4rem; min-height: 1.4em; transition: all 0.2s ease; }
.geo-message.is-success { color: var(--demo-success-fg); background-color: var(--demo-success-bg); border: 1px solid var(--demo-success-bd); }
.geo-message.is-error { color: var(--demo-error-fg); background-color: var(--demo-error-bg); border: 1px solid var(--demo-error-bd); }
.geo-sim-row { display: flex; gap: 0.5rem; justify-content: center; margin-bottom: 1.3rem; }
.geo-sim-btn { display: flex; align-items: center; gap: 0.3rem; border: 1px solid var(--line); background: var(--paper);
border-radius: 6px; padding: 0.35rem 0.7rem; font-size: 0.68rem; font-weight: 600; cursor: pointer; color: var(--ink-soft); }
.geo-sim-btn:hover { border-color: var(--accent); color: var(--accent); }
.geo-sim-btn .geo-icon { width: 12px; height: 12px; }
/* --- console --- */
.geo-console-panel { max-width: 520px; margin: 0 auto 1.2rem; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.geo-console-head { display: flex; align-items: center; justify-content: space-between; padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--line); background: var(--paper-alt); font-family: var(--mono-font); font-size: 0.7rem;
font-weight: 700; color: #888; }
.geo-clear-btn { background: none; border: none; color: var(--ink-soft); font-family: var(--mono-font); font-size: 0.64rem;
cursor: pointer; padding: 0.15rem 0.4rem; border-radius: 4px; }
.geo-clear-btn:hover { color: var(--accent); background: var(--accent-soft); }
.geo-console { min-height: 6.5rem; max-height: 9rem; overflow-y: auto; background: #1e1e1e; padding: 0.5rem 0.7rem; }
.geo-console-line { font-family: var(--mono-font); font-size: 0.68rem; color: #d4d4d4; padding: 0.08rem 0; animation: geo-pop-in 0.2s ease; white-space: pre-wrap; }
.geo-console-line.is-echo { color: #7fb0ff; }
.geo-console-line.is-success { color: #9fd9a8; padding-left: 0.9rem; }
.geo-console-line.is-error { color: #e88; padding-left: 0.9rem; }
.geo-console-empty { font-family: var(--mono-font); font-size: 0.68rem; color: #6b6b6b; }
@keyframes geo-pop-in { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: translateY(0); } }
/* --- legend --- */
.geo-legend { display: flex; gap: 0.5rem; justify-content: center; flex-wrap: wrap; max-width: 620px; margin: 0 auto; }
.geo-chip { display: flex; align-items: center; gap: 0.35rem; border: 1px solid var(--line); border-radius: 20px;
padding: 0.32rem 0.7rem; font-family: var(--mono-font); font-size: 0.64rem; color: var(--ink-soft);
transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease; }
.geo-chip .geo-icon { width: 12px; height: 12px; }
.geo-chip.is-firing { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.geo-note { text-align: center; font-size: 0.78rem; color: var(--ink-soft); padding-top: 1.4rem; max-width: 560px; margin: 0 auto; }
.geo-note strong { color: var(--ink); }
@media (prefers-reduced-motion: reduce) {
.infographic-geolocation *, .infographic-geolocation *::before, .infographic-geolocation *::after {
animation-duration: 0.001ms !important; transition-duration: 0.001ms !important;
}
}
</style>
<div class="geo-wrap">
<div class="geo-hero">
<h1>Geolocation API</h1>
<p>one call, two possible callbacks — onSuccess or onError</p>
</div>
<div class="geo-card">
<button class="geo-btn" id="geoShowBtn" type="button">
<span class="geo-icon" id="geoBtnIcon"></span>Show my location
</button>
<div class="geo-message" id="geoMessage"></div>
</div>
<div class="geo-sim-row">
<button class="geo-sim-btn" id="geoSimSuccess" type="button"><span class="geo-icon" id="geoSimSuccessIcon"></span>simulate success</button>
<button class="geo-sim-btn" id="geoSimError" type="button"><span class="geo-icon" id="geoSimErrorIcon"></span>simulate error</button>
</div>
<div class="geo-console-panel">
<div class="geo-console-head">
<span>>_ event log</span>
<button class="geo-clear-btn" id="geoClearBtn" type="button">clear</button>
</div>
<div class="geo-console" id="geoConsole">
<div class="geo-console-empty">// click "Show my location" to begin</div>
</div>
</div>
<div class="geo-legend">
<span class="geo-chip" data-evt="check"><span class="geo-icon" id="geoChipIcon0"></span>feature check</span>
<span class="geo-chip" data-evt="request"><span class="geo-icon" id="geoChipIcon1"></span>getCurrentPosition</span>
<span class="geo-chip" data-evt="success"><span class="geo-icon" id="geoChipIcon2"></span>onSuccess</span>
<span class="geo-chip" data-evt="error"><span class="geo-icon" id="geoChipIcon3"></span>onError</span>
</div>
</div>
</div>
<script>
(function () {
const wrapper = document.currentScript.closest('.infographic-geolocation')
|| document.querySelector('.infographic-geolocation');
const bodyAttr = document.body.getAttribute('data-darkmode');
let dark;
if (bodyAttr === 'true') {
dark = true;
} else if (bodyAttr === 'false') {
dark = false;
} else {
const match = document.cookie.match(/(?:^|;\s*)darkMode=([^;]+)/);
dark = match ? match[1] === 'true' : false;
}
if (dark) wrapper.setAttribute('data-theme', 'dark');
const ICONS = {
pin: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0"/><circle cx="12" cy="10" r="3"/></svg>',
play: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" stroke="none"><polygon points="6 3 20 12 6 21 6 3"/></svg>',
check: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.801 10A10 10 0 1 1 17 3.335"/><path d="m9 11 3 3L22 4"/></svg>',
xcircle: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/></svg>',
scan: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7V5a2 2 0 0 1 2-2h2"/><path d="M17 3h2a2 2 0 0 1 2 2v2"/><path d="M21 17v2a2 2 0 0 1-2 2h-2"/><path d="M7 21H5a2 2 0 0 1-2-2v-2"/></svg>'
};
wrapper.querySelector('#geoBtnIcon').innerHTML = ICONS.pin;
wrapper.querySelector('#geoSimSuccessIcon').innerHTML = ICONS.play;
wrapper.querySelector('#geoSimErrorIcon').innerHTML = ICONS.play;
wrapper.querySelector('#geoChipIcon0').innerHTML = ICONS.scan;
wrapper.querySelector('#geoChipIcon1').innerHTML = ICONS.pin;
wrapper.querySelector('#geoChipIcon2').innerHTML = ICONS.check;
wrapper.querySelector('#geoChipIcon3').innerHTML = ICONS.xcircle;
const message = wrapper.querySelector('#geoMessage');
const showBtn = wrapper.querySelector('#geoShowBtn');
const simSuccessBtn = wrapper.querySelector('#geoSimSuccess');
const simErrorBtn = wrapper.querySelector('#geoSimError');
const consoleEl = wrapper.querySelector('#geoConsole');
const clearBtn = wrapper.querySelector('#geoClearBtn');
function logLine(text, cls) {
if (consoleEl.querySelector('.geo-console-empty')) consoleEl.innerHTML = '';
const line = document.createElement('div');
line.className = 'geo-console-line ' + (cls || '');
line.textContent = text;
consoleEl.appendChild(line);
consoleEl.scrollTop = consoleEl.scrollHeight;
}
function flashChip(evt) {
const chip = wrapper.querySelector('.geo-chip[data-evt="' + evt + '"]');
if (!chip) return;
chip.classList.add('is-firing');
clearTimeout(chip._t);
chip._t = setTimeout(() => chip.classList.remove('is-firing'), 500);
}
function onSuccessDemo(lat, lng) {
message.className = 'geo-message is-success';
message.textContent = 'Your location: (' + lat + ',' + lng + ')';
logLine('onSuccess \u25b8 {latitude: ' + lat + ', longitude: ' + lng + '}', 'is-success');
flashChip('success');
}
function onErrorDemo(reason) {
message.className = 'geo-message is-error';
message.textContent = 'Failed to get your location!';
logLine('onError \u25b8 ' + (reason || 'PositionError'), 'is-error');
flashChip('error');
}
showBtn.addEventListener('click', () => {
logLine('feature check \u2192 navigator.geolocation exists', 'is-echo');
flashChip('check');
logLine('> navigator.geolocation.getCurrentPosition(onSuccess, onError);', 'is-echo');
flashChip('request');
if (!navigator.geolocation) {
onErrorDemo("browser doesn't support Geolocation");
return;
}
navigator.geolocation.getCurrentPosition(
(position) => {
const lat = position.coords.latitude.toFixed(4);
const lng = position.coords.longitude.toFixed(4);
onSuccessDemo(lat, lng);
},
(err) => {
onErrorDemo(err && err.message ? err.message : 'permission denied or blocked in this embed');
},
{ timeout: 6000 }
);
});
simSuccessBtn.addEventListener('click', () => {
logLine('> navigator.geolocation.getCurrentPosition(onSuccess, onError); (simulated)', 'is-echo');
flashChip('request');
onSuccessDemo('40.7128', '-74.0060');
});
simErrorBtn.addEventListener('click', () => {
logLine('> navigator.geolocation.getCurrentPosition(onSuccess, onError); (simulated)', 'is-echo');
flashChip('request');
onErrorDemo('user denied permission (simulated)');
});
clearBtn.addEventListener('click', () => {
consoleEl.innerHTML = '<div class="geo-console-empty">// click "Show my location" to begin</div>';
message.className = 'geo-message';
message.textContent = '';
});
})();
</script>