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. 1 Проверка HTTPSНа HTTP API молчит вообще, без ошибки
  2. 2 Запрос разрешенияБраузер спрашивает пользователя. Обойти нельзя
  3. 3 Пользователь решаетРазрешил → координаты. Отказал → PERMISSION_DENIED
  4. 4 Определение позицииGPS, Wi-Fi или IP — что доступно. Может занять секунды
  5. 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.

Частые вопросы

Почему геолокация не работает на моём сайте?
Почти всегда причина одна: сайт открыт по HTTP, а не HTTPS. С 2016 года браузеры отдают Geolocation API только в защищённом контексте. Исключение — localhost для разработки.
Насколько точны координаты?
Зависит от источника. GPS на телефоне — метры, Wi-Fi — десятки метров, определение по IP на десктопе — километры. Поле accuracy возвращает радиус погрешности в метрах — всегда проверяйте его.
Можно ли получить местоположение без спроса пользователя?
Нет. Браузер обязательно показывает запрос разрешения, и отказ нужно обрабатывать. Это не обходится — и не должно: геолокация это чувствительные данные.
Чем `watchPosition` отличается от `getCurrentPosition`?
getCurrentPosition берёт координаты один раз. watchPosition подписывается на изменения и вызывает колбэк при каждом перемещении — для навигации. Его обязательно снимать через clearWatch, иначе он работает и жрёт батарею.
Нужно ли хранить координаты пользователя?
Только с явного согласия и с осторожностью: это персональные данные. Не кладите их в URL и localStorage без необходимости, а на сервер отправляйте по HTTPS.