geolocation Permission

5 min read

geolocation Permission

Overview

Web API (not chrome.* API)

navigator.geolocation.getCurrentPosition(success, error?, options?)
navigator.geolocation.watchPosition(success, error?, options?)
navigator.geolocation.clearWatch(watchId)

Position Options

Option Type Description
enableHighAccuracy boolean Use GPS if available (slower, more battery)
timeout number Milliseconds to wait for position
maximumAge number Accept cached position if younger than this (ms)

Position Object

MV3: Service Worker Workaround

Service workers do not have access to navigator.geolocation. Use an offscreen document with GEOLOCATION reason:

  1. SW creates offscreen doc with reason GEOLOCATION
  2. Send message to offscreen doc requesting position
  3. Offscreen doc calls navigator.geolocation
  4. Offscreen doc sends result back to SW
  5. SW closes offscreen doc (optional)
// background.ts (service worker)
async function getLocation(): Promise<GeolocationPosition> {
  if (!(await chrome.offscreen.hasDocument())) {
    await chrome.offscreen.createDocument({
      url: chrome.runtime.getURL('offscreen.html'),
      reasons: [chrome.offscreen.Reason.GEOLOCATION],
      justification: 'Access geolocation API'
    });
  }
  return new Promise((resolve, reject) => {
    chrome.runtime.sendMessage({ type: 'GET_LOCATION' }, (response) => {
      if (response.error) reject(new Error(response.error));
      else resolve(response.position);
    });
  });
}
// offscreen.ts
chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
  if (msg.type === 'GET_LOCATION') {
    navigator.geolocation.getCurrentPosition(
      (pos) => sendResponse({ position: pos }),
      (err) => sendResponse({ error: err.message }),
      { enableHighAccuracy: true, timeout: 10000 }
    );
    return true;
  }
});

Manifest Declaration

{
  "permissions": ["offscreen"],
  "optional_permissions": ["geolocation"]
}

Or declare geolocation as required:

{
  "permissions": ["geolocation", "offscreen"]
}

Use Cases

Code Examples

Get position from popup (direct)

navigator.geolocation.getCurrentPosition(
  (pos) => console.log(pos.coords.latitude, pos.coords.longitude),
  (err) => console.error(err.message),
  { enableHighAccuracy: true, timeout: 10000 }
);

Watch position with error handling

const watchId = navigator.geolocation.watchPosition(
  (pos) => console.log('Updated:', pos.coords.latitude, pos.coords.longitude),
  (err) => {
    if (err.code === err.PERMISSION_DENIED) console.error('Denied');
    else if (err.code === err.POSITION_UNAVAILABLE) console.error('Unavailable');
    else if (err.code === err.TIMEOUT) console.error('Timeout');
  },
  { enableHighAccuracy: true, maximumAge: 60000 }
);
navigator.geolocation.clearWatch(watchId);

Get position from service worker via offscreen

// background.ts
async function getLocation() {
  if (!(await chrome.offscreen.hasDocument())) {
    await chrome.offscreen.createDocument({
      url: 'offscreen.html',
      reasons: [chrome.offscreen.Reason.GEOLOCATION],
      justification: 'Geolocation needs document context'
    });
  }
  return new Promise((resolve, reject) => {
    chrome.runtime.sendMessage({ type: 'GET_LOCATION' }, (resp) => {
      resp.error ? reject(new Error(resp.error)) : resolve(resp.position);
    });
  });
}

Cross-References

Frequently Asked Questions

How do I get user’s location in a Chrome extension?

Use the standard Geolocation API (navigator.geolocation) in your content script. The “geolocation” permission is only needed for the background script.

Can extensions override geolocation for testing?

Yes, Chrome DevTools allows you to override geolocation for testing purposes in your content scripts. —

Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.

No previous article
No next article