Geolocation API: как определить местоположение в браузере
Содержание
О проверке кода. Примеры не запускались в браузере — в отличие от материалов по Node.js, где приводится фактический вывод. Код дан по документации MDN. Говорим прямо, а не ставим бейдж «проверено» без проверки.
Определить, где находится пользователь, браузер умеет сам. Задача выглядит на три строки, но у неё три обязательных условия, без которых код молча не работает.
Базовый запрос
navigator.geolocation.getCurrentPosition(
(position) => {
const { latitude, longitude, accuracy } = position.coords;
console.log(`Широта: ${latitude}, долгота: ${longitude}`);
console.log(`Точность: ±${accuracy} м`);
},
(error) => {
console.log('Не удалось определить:', error.message);
},
{ enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }
);
Три аргумента, и второй так же обязателен, как первый: колбэк на успех и колбэк на ошибку. Про третий — опции — ниже.
Условие первое: только HTTPS
Самая частая причина «у меня не работает». С 2016 года браузеры отдают геолокацию только в защищённом контексте.
http://site.ru → API молчит, координат нет
https://site.ru → работает
http://localhost → работает (исключение для разработки)
Это не настраивается и не обходится — часть модели безопасности. Локация — чувствительные данные, и передавать их по незашифрованному соединению браузер не даёт. Если геолокация «внезапно перестала работать после переноса на хостинг» — проверьте протокол первым делом.
Условие второе: разрешение пользователя
Браузер обязательно показывает запрос, и ответ может быть «нет». Отказ — не исключительная ситуация, а один из нормальных исходов, который нужно обработать.
navigator.geolocation.getCurrentPosition(onSuccess, (error) => {
switch (error.code) {
case error.PERMISSION_DENIED:
showMessage('Вы запретили доступ к местоположению');
break;
case error.POSITION_UNAVAILABLE:
showMessage('Местоположение недоступно');
break;
case error.TIMEOUT:
showMessage('Определение заняло слишком долго');
break;
}
});
- 1 Проверка HTTPSНа HTTP API молчит вообще, без ошибки
- 2 Запрос разрешенияБраузер спрашивает пользователя. Обойти нельзя
-
3
Пользователь решаетРазрешил → координаты. Отказал →
PERMISSION_DENIED - 4 Определение позицииGPS, Wi-Fi или IP — что доступно. Может занять секунды
-
5
Колбэк с результатом
position.coordsсlatitude,longitude,accuracy
Хороший тон — спрашивать координаты не при загрузке страницы, а по действию пользователя: клик «показать рядом со мной». Всплывающий запрос сразу при входе раздражает и часто получает отказ на автомате.
С 2020-х можно заранее узнать статус разрешения, не вызывая запрос:
const status = await navigator.permissions.query({ name: 'geolocation' });
// status.state: 'granted' | 'denied' | 'prompt'
Это позволяет не показывать кнопку тем, кто уже отказал.
Условие третье: точность непредсказуема
accuracy — радиус погрешности в метрах, и он гуляет в тысячи раз в зависимости от источника:
| Источник | Типичная точность | Когда |
|---|---|---|
| GPS | 5–20 м | телефон на улице |
| Wi-Fi | 20–100 м | город, есть сети рядом |
| Сотовые вышки | сотни метров | телефон без GPS |
| IP-адрес | километры / город | десктоп |
Всегда смотрите на accuracy. Показывать «вы здесь» с точностью до дома, когда погрешность — три километра, — значит вводить пользователя в заблуждение.
Опции влияют на источник и цену:
enableHighAccuracy: trueпросит GPS вместо Wi-Fi/IP. Точнее, но дольше и сажает батарею — включайте, только когда точность реально нужна;timeout— сколько ждать, прежде чем сдаться;maximumAge— можно ли отдать закэшированную позицию (в мс).0— только свежую.
Слежение: watchPosition
Для навигации нужны не разовые координаты, а поток обновлений:
const watchId = navigator.geolocation.watchPosition(
(pos) => updateMap(pos.coords),
(err) => console.log(err.message),
{ enableHighAccuracy: true }
);
// ОБЯЗАТЕЛЬНО снять, когда слежение больше не нужно
navigator.geolocation.clearWatch(watchId);
clearWatch не опция, а необходимость. Забытый watchPosition продолжает опрашивать GPS в фоне и разряжает телефон — та же ошибка, что незакрытый интервал в Node или неснятый слушатель события. Снимайте слежение при уходе со страницы и при закрытии карты.
Приватность: это персональные данные
Отдельно, потому что в оригинале этого не было вовсе.
Координаты — чувствительная информация. Отсюда правила:
- не кладите их в URL — попадут в логи, историю, реферер. Общее правило работы с личными данными;
- не храните без нужды. Нужны на один запрос — используйте и забудьте;
- на сервер — только по HTTPS и только с согласия;
- объясните, зачем. «Разрешите геолокацию, чтобы показать ближайшие пункты выдачи» получает согласие чаще, чем немой системный запрос.
Что было на этой странице в 2017 году
Первая версия вышла 31 июля 2017 года и разбирала getCurrentPosition с примером вывода координат. Синтаксис описан верно и не изменился.
Чего не хватало — всех трёх условий, из-за которых код не работает:
- Требование HTTPS в статье не упоминалось. В 2017-м переход на HTTPS ещё шёл, и многие сайты работали по HTTP — а значит, геолокация у половины читателей просто не запускалась, и почему — было непонятно.
- Обработка отказа подавалась как необязательная деталь. Сегодня это половина логики: пользователь отказывает часто.
- Приватности не было вовсе. Тогда о персональных данных в вебе думали мало; сейчас это обязательная часть любой работы с геолокацией.
Метод не устарел. Устарело представление, что достаточно вызвать функцию и получить координаты.
Смежные темы: геолокация с картами Google и Яндекс; что такое JavaScript — язык и браузерные API; промисы. Полный список — в уроках JavaScript.
Частые вопросы
Почему геолокация не работает на моём сайте?
Насколько точны координаты?
accuracy возвращает радиус погрешности в метрах — всегда проверяйте его.Можно ли получить местоположение без спроса пользователя?
Чем `watchPosition` отличается от `getCurrentPosition`?
getCurrentPosition берёт координаты один раз. watchPosition подписывается на изменения и вызывает колбэк при каждом перемещении — для навигации. Его обязательно снимать через clearWatch, иначе он работает и жрёт батарею.