close
Skip to content

Add support for approximate geolocation#195

Open
alvinjiooo wants to merge 5 commits intow3c:mainfrom
alvinjiooo:add-approximate-geolocation
Open

Add support for approximate geolocation#195
alvinjiooo wants to merge 5 commits intow3c:mainfrom
alvinjiooo:add-approximate-geolocation

Conversation

@alvinjiooo
Copy link
Copy Markdown

@alvinjiooo alvinjiooo commented Sep 5, 2025

Closes #182

This commit introduces the ability for users and developers to request a less precise, privacy-preserving "approximate" location.

Key changes include:

  • A new accuracyMode option in PositionOptions to request either "precise" or "approximate" location.
  • A new "Geolocation permissions" section, which include new "geolocation-approximate" powerful feature and custom precise permission query or request algorithm.
  • Updated "Request a position" and "Acquire a position" algorithms to handle the new accuracy levels and new emulation change (feat: add accuracyMode to emulation.setGeolocationOverride webdriver-bidi#1105).
  • The GeolocationCoordinates interface now includes an accuracyMode attribute to reflect the accuracy of the returned position.
  • Expanded the introduction with a non-normative description of what an "approximate location" is.
  • Added a normative privacy requirement for user agents to mitigate precise location reconstruction by caching approximate locations for a period of time.
  • Updated

The following tasks have been completed:

  • Modified Web platform tests (link to pull request)

Implementation commitment (and no objections):

Documentation (new feature):

  • Updated implementation report
  • Pinged MDN
  • Added example to README or spec

For documentation, either create an issue or pull request in MDN's Content repo - providing as much information as you can. PR is prefered.

Approximate Geolocation explainer


Preview | Diff

@alvinjiooo alvinjiooo requested a review from nondebug September 5, 2025 18:25
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
@reillyeon
Copy link
Copy Markdown
Member

For readability as you iterate on this proposal it's okay for this PR to directly change the specification text however to land this change the changes need to be enclosed in the correct candidate additions/corrections/deletions syntax.

@marcoscaceres
Copy link
Copy Markdown
Member

@reillyeon if it's ok, let's move this to CR first (i.e., let's not waste time with the ins/dels). We are close to publishing as CR again.

Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
@alvinjiooo alvinjiooo force-pushed the add-approximate-geolocation branch from 99d9b03 to 3fa8869 Compare September 22, 2025 22:49
@marcoscaceres marcoscaceres added the TPAC2025 Topics for discussion at TPAC 2025 label Oct 28, 2025
@marcoscaceres marcoscaceres requested a review from Copilot October 29, 2025 06:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for approximate location positioning to the Geolocation API specification. It introduces a privacy-preserving alternative to precise location sharing, allowing applications to request coarse-grained location data when high accuracy is not needed.

Key changes:

  • Introduces accuracyMode option with "precise" (default) and "approximate" values
  • Adds new "geolocation-approximate" permission alongside existing "geolocation" permission
  • Implements separate caching for precise and approximate positions
  • Updates permission request flows to allow users to choose between precise and approximate location sharing

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread index.html
Comment thread index.html
Comment thread index.html Outdated
Comment thread index.html
@alvinjiooo alvinjiooo force-pushed the add-approximate-geolocation branch from 3fa8869 to 8658f5a Compare December 5, 2025 19:45
@alvinjiooo alvinjiooo marked this pull request as draft December 5, 2025 20:13
@alvinjiooo alvinjiooo self-assigned this Dec 5, 2025
@alvinjiooo alvinjiooo force-pushed the add-approximate-geolocation branch 6 times, most recently from 2354ca8 to d3a4d47 Compare December 12, 2025 18:56
@alvinjiooo alvinjiooo requested a review from nondebug December 12, 2025 18:58
@alvinjiooo alvinjiooo marked this pull request as ready for review December 12, 2025 19:00
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Copy link
Copy Markdown
Member

@antosart antosart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few comments wrt the permission handling.

Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Copy link
Copy Markdown
Member

@marcoscaceres marcoscaceres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all the "Candidate addition" stuff. We don't need any of that additional markup anymore (but leave the rest of normative text there 😄 ) .

@alvinjiooo alvinjiooo force-pushed the add-approximate-geolocation branch from d3a4d47 to b0d0589 Compare January 10, 2026 04:54
Comment thread index.html
Comment thread index.html Outdated
Copy link
Copy Markdown

@nondebug nondebug left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@alvinjiooo alvinjiooo requested a review from reillyeon April 6, 2026 22:57
@alvinjiooo
Copy link
Copy Markdown
Author

Hi @reillyeon,
Will you have a chance to review this PR before it lands?
Thanks!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (1)

index.html:951

  • This uses [=list/remove=] (lowercase list), but elsewhere the spec uses [=List/remove=] for the Infra list operation. The lowercase form likely won’t resolve to the intended definition; please align the casing with the rest of the document.
              If |resolvedPermissionState| is "denied", then:
                <ol>
                  <li>If |watchId| was passed, [=list/remove=] |watchId| from
                  |watchIDs|.
                  </li>

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread index.html
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html
Copy link
Copy Markdown
Member

@marcoscaceres marcoscaceres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good @alvinjiooo ... there seems to be some unrelated editorial changes.

Maybe see about splitting those out (get Genini maybe to do them quickly?). Will make this easier to review.

Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
Comment thread index.html Outdated
[=approximate positions=]. To mitigate this risk of a refinement
attack, when a site receives an [=approximate position=], any
subsequent calls from that same site within a user-agent-defined time
window SHOULD return the exact same, cached [=approximate position=]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be in the algorithm (if it's not already).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did consider formalizing this caching logic within the algorithm. However, opinions on the practical risk of precise location reconstruction still vary, and there isn't a single standardized approach yet. Coupled with the existing visibility requirements, a caching window (like 15 minutes) already makes reconstruction extremely difficult in practice. Keeping this in the Privacy Considerations section provides strong guidance while leaving implementers flexibility as mitigation strategies evolve. I’m inclined to leave it as a 'SHOULD' recommendation rather than a hard algorithmic requirement for now, but I'd be interested to hear your thoughts on this framing.

Comment thread index.html Outdated
Comment thread index.html
<dl class="switch">
<dt id="permission-denied">
User or system denied permission:
<li data-cite="infra">If acquiring the position data from the
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change seems unrelated or maybe the white space got screwed up?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is not changed by the PR, the original place is at here. It got moved further down because the introduced change for approximate geolocation.

Comment thread index.html
</ol>
</li>
</ol>
<dl class="switch">
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this belong in this PR? Can it be a separate PR?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is not changed too, the original place is at here.

- Rephrase privacy risk mitigation and user choice framing for clarity and neutrality.
- Update terminology from 'powerful features' to 'permissions' and 'protecting' to 'obscuring'.
- Add cross-references to the 'acquire a position' algorithm and AccuracyMode enum values.
- Fix ReSpec linking errors and IDL formatting.
- Remove redundant MUST statements from informative notes.
- Tidy index.html.
@alvinjiooo alvinjiooo requested a review from marcoscaceres April 8, 2026 07:29
@marcoscaceres
Copy link
Copy Markdown
Member

Really nice work getting this to a reviewable state, @alvinjiooo.

I want to raise a privacy concern about two pieces: GeolocationPermissionStatus and coords.accuracyMode.

The design lets sites request approximate via PositionOptions.accuracyMode, which is great for data minimization. But I think we should stop there and not tell the site what the user actually chose.

GeolocationPermissionStatus: This exposes the user's privacy preference via navigator.permissions.query() without any position request. There's no precedent for permission result types exposing user preference metadata (camera doesn't reveal which device was selected, notifications doesn't reveal quiet mode). This is closely related to the long-standing concern in w3c/permissions#52 — expanding the queryable surface to include how a user configured their privacy preference compounds the risk. I'd propose removing this entirely, and making "geolocation-approximate" not a JS-queryable permission name. Only "geolocation" should be valid for permissions.query(). This keeps the API backwards-compatible: sites cannot use permissions.query() to pre-detect whether approximate location is available or what the user chose, preserving the same opacity as a UA that doesn't support the feature.

coords.accuracyMode: Today, coords.accuracy of 5000m is ambiguous: it could be the user's privacy choice, bad GPS lock, or WiFi-only positioning. That ambiguity prevents reliable upgrade-nagging. A definitive "approximate" flag removes that ambiguity and enables "tap here for better location" dark patterns. I'd propose removing this attribute.

Permissions Policy gating: I think "geolocation-approximate" still has value as a policy-controlled feature for iframe restriction. But the allowed to use check in the algorithm (currently only checking "geolocation") needs updating: if accuracyMode is "approximate", check allowed to use "geolocation-approximate"; if "precise", check allowed to use "geolocation". And allowing "geolocation" should implicitly allow "geolocation-approximate" (superset), but not vice versa.

Summary:

  • Keep PositionOptions.accuracyMode (site requests what it needs)
  • Keep "geolocation-approximate" for Permissions Policy (iframe control)
  • Remove GeolocationPermissionStatus (no custom permission result type)
  • Remove coords.accuracyMode (site doesn't learn what user chose)
  • Only "geolocation" is queryable via Permissions API
  • Add proper allowed to use checks per accuracy mode

I'd like to invite @martinthomson, @saschanaz, and @npdoty to weigh in on the privacy model here. Once we converge on the right shape, I think this warrants a formal PING review given the sensitivity of location privacy.

Copy link
Copy Markdown
Member

@marcoscaceres marcoscaceres left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #195 (comment) ... as I think the permission model needs a significant overhaul... and could be simultaneously significantly simplified.

Comment thread index.html
</pre>
</aside>
<p>
Similarly, you can request a cached approximate position.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Similarly, you can request a cached approximate position.
Similarly, you can request a cached approximate position:

Comment thread index.html
successCallback,
console.error,
{ maximumAge: 600_000 }
{ maximumAge: 600_000 } // `accuracyMode` defaults to "precise"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{ maximumAge: 600_000 } // `accuracyMode` defaults to "precise"
{
maximumAge: 600_000,
// `accuracyMode` defaults to "precise"
}

Comment thread index.html
new position.
</p>
<aside class="example" title="Getting cached position">
<aside class="example" title="Getting a cached precise position">
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a nit... but it feels like we could cover both cases with just one example.

Comment thread index.html
The {{PositionOptions/accuracyMode}} option enhances user privacy by
providing websites with the choice to request an [=approximate
position=]. This allows applications to function without needing the
user's [=precise position=], thus offering a more privacy-friendly
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
user's [=precise position=], thus offering a more privacy-friendly
user's [=precise position=], thus offering a more privacy-preserving

Comment thread index.html
Comment on lines +408 to +409
the user agent can provide a less precise location that still meets the
application's needs while obscuring the user's [=precise position=].
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The user agent can't know if the position will meet the sites needs. It can only return an approximate position. If it's good enough, that's up to the site to determine.

Suggested change
the user agent can provide a less precise location that still meets the
application's needs while obscuring the user's [=precise position=].
a supporting user agent MUST provide a less precise location,
obscuring the user's [=precise position=].

Comment thread index.html
(for approximate location).
</p>
<p>
There is a strict dependency between the [=permission state=]s of
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
There is a strict dependency between the [=permission state=]s of
There is a strict dependency between the [=permission states=] of

Comment thread index.html
implies denying a [=precise position=]. This results in the following
allowed combinations of states:
</p>
<ul>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I wonder if this should be a table?

Comment thread index.html
<p>
Implementers MUST ensure that these states remain coherent. For
example, if a user changes the [=permission state=] of
<a>"geolocation-approximate"</a> to [=permission/"denied"=] via site
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but this needs to be an algorithm. We can wire up the Permission side later, but this still needs to be algorithmically defined.

Basically, the algorithm receives the new state, and then it dos all the things defined here.

Comment thread index.html
<p>
Implementers MUST ensure that these states remain coherent. For
example, if a user changes the [=permission state=] of
<a>"geolocation-approximate"</a> to [=permission/"denied"=] via site
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this can be very racy, so some kind of coordinator will still be needed where this is queued.

Comment thread index.html
while <a>"geolocation"</a> is a [=powerful feature=] with:
</p>
<ul>
<li>A custom [=powerful feature/permission result type=]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to leak the user's choice? This seems like it shouldn't be needed. The site should just get back a portion, but it shouldn't know what the user selected or when it's changed, right?

@antosart
Copy link
Copy Markdown
Member

Wrt leaking the granted accuracy (either in GeolocationPermissionStatus or in coords.accuracyMode) our main thought was that in practice there is no real way to hide this (on Android, for example, a coarsened position has a fixed accuracy - I believe it's 2000m - and the possible values for the x and y coords are on a grid, so that it seems clear that the position is artificially coarsened and not the result of bad GPS signal).

As for the geolocation-approximate permission policy, I agree there is value in having it. However, it's not totally trivial how to make it work correctly because of the interdependencies between geolocation and geolocation-approximate, which are not currently supported by the Permission Policy specification (see explainers-by-googlers/approximate-geolocation#19 and explainers-by-googlers/approximate-geolocation#20 for more details).

@marcoscaceres
Copy link
Copy Markdown
Member

marcoscaceres commented Apr 21, 2026

I get that Android's current LocationFudger implementation snaps to a grid, which makes approximate positions detectable in practice. But I think the right response is to encourage UAs to add entropy (jitter, noise, variable quantization) to make approximate less detectable, rather than formalizing the leak with coords.accuracyMode. The browser doesn't have to pass the OS's accuracy value or grid pattern through to JS unchanged. Chrome on Android could add noise to the grid-snapped position before delivering it to content, making grid detection unreliable.

The spec should push implementations toward privacy (guidance on resisting detectability), not codify worst-case current behavior as the API surface.

On the "sites need to know" argument: I think there are two legitimate needs here, and neither requires coords.accuracyMode:

  1. Pre-permission capability detection ("does this browser support approximate?"): A CSS media feature would let sites adapt their UI before ever calling the API, e.g., showing "we only need your city-level location" messaging. This is pure capability detection, no user preference leak.

  2. Post-permission UX adaptation ("is this position good enough for walking directions?"): coords.accuracy already answers this. If accuracy is 3000m, you show city-level features regardless of whether that's approximate mode, bad GPS, or WiFi-only positioning. The site should be checking the number anyway. And even with accuracyMode: "approximate", the UA could return a position with 50m accuracy (the request is a hint, not a guarantee), so the site can't rely on the label for UX decisions.

So the model would be: CSS media feature for capability → PositionOptions.accuracyMode for request → coords.accuracy for adaptation. No flag that reveals the user's privacy choice.

On Permissions Policy: agreed it's non-trivial. I've looked at issues explainers-by-googlers/approximate-geolocation#19 and explainers-by-googlers/approximate-geolocation#20 in the explainer repo. The inheritance problem needs upstream Permissions Policy spec work, but that seems like the right path rather than working around it.

@antosart
Copy link
Copy Markdown
Member

Note that for pre-permission capability detection, as pointed out here, we don't really need anything, and our initial proposal to expose this explicitly was objected to.

@marcoscaceres
Copy link
Copy Markdown
Member

I’m not fully following. What I’m saying is that using JS with a getter that throws is a very cool hack (TIL 🤯), but using a CSS media feature would be better developer ergonomics for the intended use case.

@antosart, would like to hear your thoughts on the overall reworked proposal.

@marcoscaceres
Copy link
Copy Markdown
Member

Regarding the discussion on whether sites need to know the accuracy level via GeolocationPermissionStatus:

I wanted to share some implementation context. WebKit already masks the geolocation permission state returned by permissions.query() as a fingerprinting countermeasure. Specifically, if a page hasn't called the Geolocation API, permissions.query({name: "geolocation"}) returns "prompt" regardless of the actual permission state (see WebKit commit 386b21d).

The rationale: the true permission state should only be revealed to a site that is willing to show a prompt. This prevents silent fingerprinting via the Permissions API.

Adding GeolocationPermissionStatus with an accuracyMode attribute would create a new, more detailed information channel that bypasses this protection. A site could learn not just whether geolocation is granted, but how the user configured their privacy preference, all without triggering any prompt.

This reinforces the proposal I outlined earlier: keep PositionOptions.accuracyMode (sites declare what they need), but don't expose the user's choice back to the site via the Permissions API. The existing coords.accuracy value on the returned position gives the site everything it needs to adapt its UX.

@antosart
Copy link
Copy Markdown
Member

I wanted to share some implementation context. WebKit already masks the geolocation permission state returned by permissions.query() as a fingerprinting countermeasure. Specifically, if a page hasn't called the Geolocation API, permissions.query({name: "geolocation"}) returns "prompt" regardless of the actual permission state (see WebKit commit 386b21d).

I am aware that WebKit implements this additional masking. For the granted accuracyMode the story seems different to me, since that would anyway be exposed only if the returned permission state is "granted". If the permission state is "granted" the site can call getCurrentPosition() and examine the returned geolocation anyway, and it seems to me that the information about the accuracyMode granted by the user doesn't really leak much more at that point.

That said, I don't have a super strong opinion about this. We added it to the proposal because it seemed ergonomic to offer web developers this information and it didn't seem to expose anything that wasn't already leaked. But I believe we would be fine with dropping it. I would suggest leaving the possibility to query "geolocation-approximate" for simplicity, since a browser like WebKit can anyway mask it as it does for "geolocation" so IIUC that wouldn't change basically anything for WebKit.

For capability detection, it's not immediately clear to me that a CSS media feature is needed for this particular capability (I mean, why would it make sense for approximate geolocation support in particular to be detected via CSS media feature and not for any of the thousands of other Web APIs?). But I am happy to defer to people who are more expert than me.

For the "geolocation-approximate" permission policy, I agree we should have it. The blocker is just how to spec it properly. It seems feasible to me to add it in a follow-up change though, no?

Summary

So my proposal would be:

  1. If exposing the granted accuracyMode is a blocker for you, let's drop it (i.e. let's drop GeolocationPermissionStatus and remove coords.accuracyMode - but keep the permission "geolocation-approximate" if that's acceptable for you).
  2. Can we punt capability detection for now? If needed, we can always add it later.
  3. Let's add "geolocation-approximate" Permission Policy. If it's acceptable for you, we can add it in a second PR after we figure out the changes needed to the Permission Policy infrastructure and we implement them in the Permission Policy spec.

@marcoscaceres how does this sound?

@reillyeon
Copy link
Copy Markdown
Member

@marcoscaceres, regarding "post-permission UX adaptation" a use case for this is not just adapting the UX to approximate vs. precise positioning but also informing the user that there are steps they could take to allow the site to function better. For example should they make sure their phone has a clear view of the sky (to improve GPS accuracy) or should they consider granting precise location permission. I acknowledge that "permissions pestering" is a non-goal but we should consider ways to allow the site and browser to give the user a clear path to a potentially desirable experience. Maybe this is something the <geolocation> element can resolve.

@marcoscaceres
Copy link
Copy Markdown
Member

@antosart, thank you for the thoughtful summary. I think we're very close.

On your three points

1. Dropping GeolocationPermissionStatus and coords.accuracyMode: Agreed. For "geolocation-approximate", we should have it as a Permission Policy token (for iframe restriction). Making it queryable via permissions.query() is fine for completeness, but it would just be treated the same as "geolocation" and adds no significant value: before calling the API, the state would be masked (as WebKit does for "geolocation"); after the call, the site already has its answer in the returned position. Having only "geolocation" queryable is also simpler for developers: two queryable permission names raises questions about whether they can differ, whether one can change independently of the other, and whether you need separate PermissionStatus event watchers for each. For example:

const geo = await navigator.permissions.query({ name: "geolocation" });
const geoApprox = await navigator.permissions.query({ name: "geolocation-approximate" });

// Can these differ? What if geo is "denied" but geoApprox is "granted"?
// What if the user revokes one but not the other?
// Do I need to watch both?
geo.onchange = () => updateUI();
geoApprox.onchange = () => updateUI();

That's unnecessary complexity for no practical benefit.

2. Deferring capability detection: Agreed. The getter-that-throws pattern works today. We can revisit a CSS media feature or other mechanism later if there's demand.

3. Permission Policy sequencing: I'd prefer to land the Permission Policy in this PR rather than a follow-up. Since we're already going to rework the PR to remove GeolocationPermissionStatus and coords.accuracyMode, the Permission Policy changes can go in at the same time. Splitting it means there's a window where approximate geolocation exists without iframe restrictions, which is the wrong default.

Since we're converging on a smaller API surface, the PR will need a rework. I'm happy to help with that, either collaborating on the changes together or drafting the updates myself if that's easier. @alvinjiooo, what would you prefer?

On UX adaptation (@reillyeon)

@reillyeon, I think the use case you're describing ("tell the user to get a clear view of the sky" vs. "consider granting precise") assumes a relatively static scenario. In practice, coords.accuracy is extremely dynamic. A user walking through a city will see accuracy swing wildly: tight on open streets, wide between buildings, tight again crossing a park, wide entering a subway. With watchPosition(), these values can change dramatically from one callback to the next just because someone turned a corner or stepped out of a lift.

Telling a user "go outside for better GPS" based on a momentary accuracy reading would be poor UX, because the value might improve on its own 30 seconds later. And this volatility applies regardless of whether the user chose approximate or has a bad signal. Even with coords.accuracyMode, the site couldn't reliably distinguish the two cases in a way that would produce good guidance.

The practical approach is for sites to work with whatever accuracy they get and degrade gracefully. If accuracy is consistently insufficient, a general "location isn't precise enough for this feature" message covers both cases without trying to diagnose the cause. That's also the privacy-preserving approach.

I think you're right that the <geolocation> element could be interesting for richer UA-mediated experiences, but that's a separate conversation and shouldn't block this PR.

@marcoscaceres
Copy link
Copy Markdown
Member

To make sure we're on the same page, here's what I think we're converging on:

  1. Keep PositionOptions.accuracyMode (site declares what accuracy it needs)
  2. Drop GeolocationPermissionStatus (don't expose user's choice via Permissions API)
  3. Drop coords.accuracyMode (preserve the ambiguity of coords.accuracy)
  4. Add "geolocation-approximate" as a Permission Policy token (iframe restriction)
  5. Only "geolocation" queryable via permissions.query()
  6. Defer capability detection (CSS media feature or otherwise) to a future PR
  7. Rework the PR to reflect the above

@antosart @alvinjiooo @reillyeon, does this match your understanding?

@antosart
Copy link
Copy Markdown
Member

To clarify: we still need a separate "geolocation-approximate" permission (aka powerful feature) in order to store the user preference (approx/precise) right?

On "geolocation-approximate"

Wrt having "geolocation-approximate" queryable or not: there are cases in which "geolocation-approximate" and "geolocation" would have different return values, for example if the user grants approximate after a call to getCurrentPosition({'accuracyMode': 'approximate'}) then "geolocation-approximate" would be granted while "geolocation" would still be prompt. I think the behaviour makes sense and is important since it does not lock in websites which ask for approximate location only (because they can always upgrade in the future if they need to). I think this can make adoption of approximate location easier. Also, for browser with one-time + permanent permissions like chrome, this can enable permanent approximate location grants + one-time (when needed) precise location upgrades, which might be a good compromise in a number of situations.

With that in mind, I think it's nice to keep the invariant that getCurrentPosition({accuracyMode}) prompts/returns/throws iff permissions.query(accuracyMode) prompts/returns/throws. Note how this also makes it possible to introduce approx location in a backwards compatible way (given that accuracyMode defaults to precise if empty). That's why I would really insist that it makes sense to keep "geolocation-approximate" queryable.

Wrt permission policy

I tried to dig a bit in the Permission Policy spec, and for properly supporting "geolocation-approximate" as a policy-controlled feature I think we need to (a) change Define an inherited policy... so that "geolocation-approximate" can be enabled in subframes if either geolocation or geolocation-approximate is returned in Permissions Policy or allowed in the iframe attribute, and (b) add an effective declared policy so that geolocation-approximate's effective declared policy is the union of geolocation and geolocation-approximate's declared policy.

I see two ways of doing this:

  1. Allow policy-controlled feature to arbitrarily override those algorithms, similar as what the Permissions spec does, or
  2. Implement in the Permission Policy spec a concept of dependent features, and adapt the algorithms above to take dependencies into account.

I would personally say that option 2. is probably easier and nicer, but I guess we should have that discussion on the Permission Policy spec and with the editors. In any case, it seems quite some work.

What I've been seeing in other specs is adding a note with how something would work if things where allowed by another spec even if they are not. That could unblock us here even with the dependency on Permissions Policy, but I am not sure it's a good model.

But I would ask again if you really think that we can't decouple the "geolocation-approximate" permission policy in a separate PR here. In any case, approximate geolocation is currently gated (as specced in the current version of the PR) by the "geolocation" policy-controlled feature. What we are missing is just a more granular way for websites to allow only approximate and not precise geolocation in third party contexts. While very nice to have (and we should definitely find a way to support it!), it does not seem blocking to me.

@alvinjiooo
Copy link
Copy Markdown
Author

@antosart, thank you for the thoughtful summary. I think we're very close.

On your three points

1. Dropping GeolocationPermissionStatus and coords.accuracyMode: Agreed. For "geolocation-approximate", we should have it as a Permission Policy token (for iframe restriction). Making it queryable via permissions.query() is fine for completeness, but it would just be treated the same as "geolocation" and adds no significant value: before calling the API, the state would be masked (as WebKit does for "geolocation"); after the call, the site already has its answer in the returned position. Having only "geolocation" queryable is also simpler for developers: two queryable permission names raises questions about whether they can differ, whether one can change independently of the other, and whether you need separate PermissionStatus event watchers for each. For example:

const geo = await navigator.permissions.query({ name: "geolocation" });
const geoApprox = await navigator.permissions.query({ name: "geolocation-approximate" });

// Can these differ? What if geo is "denied" but geoApprox is "granted"?
// What if the user revokes one but not the other?
// Do I need to watch both?
geo.onchange = () => updateUI();
geoApprox.onchange = () => updateUI();

That's unnecessary complexity for no practical benefit.

2. Deferring capability detection: Agreed. The getter-that-throws pattern works today. We can revisit a CSS media feature or other mechanism later if there's demand.

3. Permission Policy sequencing: I'd prefer to land the Permission Policy in this PR rather than a follow-up. Since we're already going to rework the PR to remove GeolocationPermissionStatus and coords.accuracyMode, the Permission Policy changes can go in at the same time. Splitting it means there's a window where approximate geolocation exists without iframe restrictions, which is the wrong default.

Since we're converging on a smaller API surface, the PR will need a rework. I'm happy to help with that, either collaborating on the changes together or drafting the updates myself if that's easier. @alvinjiooo, what would you prefer?

On UX adaptation (@reillyeon)

@reillyeon, I think the use case you're describing ("tell the user to get a clear view of the sky" vs. "consider granting precise") assumes a relatively static scenario. In practice, coords.accuracy is extremely dynamic. A user walking through a city will see accuracy swing wildly: tight on open streets, wide between buildings, tight again crossing a park, wide entering a subway. With watchPosition(), these values can change dramatically from one callback to the next just because someone turned a corner or stepped out of a lift.

Telling a user "go outside for better GPS" based on a momentary accuracy reading would be poor UX, because the value might improve on its own 30 seconds later. And this volatility applies regardless of whether the user chose approximate or has a bad signal. Even with coords.accuracyMode, the site couldn't reliably distinguish the two cases in a way that would produce good guidance.

The practical approach is for sites to work with whatever accuracy they get and degrade gracefully. If accuracy is consistently insufficient, a general "location isn't precise enough for this feature" message covers both cases without trying to diagnose the cause. That's also the privacy-preserving approach.

I think you're right that the <geolocation> element could be interesting for richer UA-mediated experiences, but that's a separate conversation and shouldn't block this PR.

@marcoscaceres , thanks for discussion and sharing the thoughts!
I can continue updating this PR since we are close to the final alignment. Antonio shared some good thoughts in latest comment. Let's see if that make sense to you then I will start the work to update this PR.
Thanks!

@marcoscaceres
Copy link
Copy Markdown
Member

@antosart, you're right that the two permissions can have genuinely different states. That's a real distinction.

But I think the progressive UX belongs in the UA's permission dialog, not in the site-queryable API. A UA can offer "approximate or precise?" in a single prompt (or do permanent-approximate + one-time-precise) without the site learning which tier the user chose. The site adapts to coords.accuracy, which gives it everything it needs.

Making both queryable creates concerns:

  1. Preference leakage: "approximate granted, precise prompt" tells the site "this user actively chose to withhold precise." That's a behavioral signal about privacy sensitivity, available via permissions.query() before any position request and without a user gesture. Yes, coords.accuracy reveals something after the API is called, but that requires the user to actively grant permission and the site to make a request. A queryable permission state is a passive, persistent signal. For precedent, the Notifications API doesn't expose quiet mode or do-not-disturb; the site just learns granted/denied/default. The pattern is to hide user configuration choices within a granted capability.

  2. Dark patterns: A site that detects approximate-granted can target upgrade prompts. With a single permission, the site can't distinguish user choice from signal quality from UA policy, removing this lever.

  3. Revocation signals: With permanent approximate + one-time precise, PermissionStatus.onchange fires when the one-time grant expires, giving the site a real-time signal about privacy state changes.

  4. Fingerprinting surface: UAs that mask permission state (returning "prompt" until the API is actually called) would need to mask two permissions instead of one, with consistent interaction between the two masked states. This increases complexity for privacy-preserving implementations while giving a richer signal to implementations that don't mask.

The progressive UX works identically under a single permission. A progressive app requests approximate, later requests precise; the UA re-prompts if needed. The only difference: the site can't detect why accuracy is what it is. That opacity is the privacy feature.

Your invariant (getCurrentPosition({accuracyMode}) matches permissions.query(accuracyMode)) is elegant, but it optimizes for developer ergonomics at the cost of user privacy. The invariant we should preserve is: the site learns what accuracy it received, never what the user chose.

Note that accuracyMode is a soft hint, not a hard gate: if you request {accuracyMode: "precise"} and the UA gives you approximate, getCurrentPosition() still succeeds. The API always returns a position. This is the same pattern as enableHighAccuracy today: a site can request high accuracy and get low accuracy without any error, and nobody argued that enableHighAccuracy needs a separate queryable permission. So permissions.query({name: "geolocation"}) should return "granted" when the user has granted any level of geolocation access.

Existing implementation precedent

This model isn't theoretical. In WebKit's iOS implementation, Safari's per-site geolocation prompt is a simple Allow/Don't Allow. The accuracy level is determined by the OS-level permission on the app, not by the website or the per-site prompt. The site gets allow or deny; the accuracy of the position it receives depends on what the OS provides. The website never gets to query which accuracy tier the user configured.

This is exactly the model we're proposing for the spec: one permission grant, accuracy controlled by the UA/OS, opaque to content.

On Permission Policy

I take your point about the complexity of the Permission Policy spec changes. I looked into it and the iframe-restriction use case (granting a cross-origin iframe approximate-only access) genuinely requires upstream changes to the Permissions Policy spec's inherited policy algorithms. There's no clean local workaround. I'm OK with decoupling this into a follow-up PR, since approximate is already gated by the "geolocation" policy-controlled feature. I'll file an issue on the Permissions Policy spec to start that work in parallel.

On capability detection

This is already solved without spec changes. WebIDL's dictionary member processing means sites can detect accuracyMode support via a getter on the options object:

function supportsAccuracyMode() {
  try {
    navigator.geolocation.getCurrentPosition(() => {}, () => {}, {
      get accuracyMode() { throw new Error('supported'); }
    });
  } catch (e) {
    return e.message === 'supported';
  }
  return false;
}

I verified this works in Safari today (throws on enableHighAccuracy since accuracyMode isn't implemented yet; would throw on accuracyMode once it is). We can add a non-normative note about this pattern in the spec.

Updated summary

  1. Keep PositionOptions.accuracyMode
  2. Drop GeolocationPermissionStatus
  3. Drop coords.accuracyMode
  4. Only "geolocation" queryable via permissions.query()
  5. Add non-normative note on capability detection (getter pattern, already works)
  6. Defer "geolocation-approximate" Permission Policy to a follow-up PR (requires upstream Permissions Policy spec work; I'll file the issue)
  7. Recommend (non-normatively) that UAs offer users a tiered choice (approximate vs. precise) in their permission UI

Point 7 captures the progressive UX benefit without encoding user choices as queryable API state.

@alvinjiooo, I think you can start the rework. Happy to collaborate on the spec text.

@antosart @reillyeon, does this work?

@antosart
Copy link
Copy Markdown
Member

I'd like to argue again on why I believe that allowing to query "geolocation-approximate" is important.

First of all, I actually believe that makes developers life easier. Again, the model would be that geolocation.getCurrentPosition(accuracyMode) prompts/throws/returns iff permissions.query(accuracyMode) returns "prompt"/"denied"/"granted" respectively. So a site using precise location (or a legacy site) would just do:

const geo = await navigator.permissions.query({ name: "geolocation" });
geo.onchange = (status) => {if (status === 'granted') navigator.geolocation.getCurrentPosition()};

while a site which is fine with approx-only location can write:

const geoApprox = await navigator.permissions.query({ name: "geolocation-approximate" });
geoApprox.onchange = (status) => {
  if (status === 'granted')
     navigator.geolocation.getCurrentPosition({accuracyMode: 'approximate'})};

and work exactly the same way without running into the edge cases in which one of the two permission states changes independently of the other one.

A very concrete use case, which might currently be Chrome specific but I believe is nevertheless meaningful, is the following:

Chrome can display different permission prompts based on the expectation of whether the user will want to grant or not. When chrome believes the likelihood is low, a omnibox chip is displayed and the geolocation request is autorejected. Users can still go into settings/page info and grant location access: in that case, the onchange() event fires in the page and the page can react and query geolocation. Chrome actually tracks whether the page is listening to onchange(), and suggests the user to reload the page is that's not the case (since the user is explicitly enabling geolocation, they likely expect some functionality on the page to start working, but if the page does not react on the permission change event it's likely it needs a reload). We would like to keep this flow working, and for it to seamlessly work both for getCurrentPostion(approximate) and for getCurrentPosition(precise).

For that to be the case, we do need the "geolocation-approximate" permission to be queryable, as that's the only way for a site to be able to use getCurrentPosition(approximate) and have everything working. If only "geolocation" is queryable, but "geolocation-approximate" is not, a user changing the geolocation setting in the browser UI from (approx:prompt, precise:prompt) to (approx:granted, precise:prompt) would not trigger an onchange event for "geolocation".

Given the fact that WebKit can still mask the returned value of "geolocation-approximate" (and actually it seems even spec compliant to throw when that permission state is queried, see the Note in https://www.w3.org/TR/permissions/#query-method), I don't see why it would be a problem to have that.

@reillyeon
Copy link
Copy Markdown
Member

@antosart, I think @marcoscaceres's suggestion here implies that geo.onchange would fire regardless of whether the user later granted approximate or precise geolocation through browser/OS UI. This would enable the flow you describe above while hiding from the developer which type of permission the user chose to grant (other than by observing accuracy).

@antosart
Copy link
Copy Markdown
Member

@antosart, I think @marcoscaceres's suggestion here implies that geo.onchange would fire regardless of whether the user later granted approximate or precise geolocation through browser/OS UI. This would enable the flow you describe above while hiding from the developer which type of permission the user chose to grant (other than by observing accuracy).

onchange can fire only if the permission state changes (otherwise it doesn't make much sense).

For how we designed things (as specced in this PR and as currently prototyped in chrome), the permissions (approximate, precise) (i.e. "geolocation-approximate" and "geolocation") can have 6 possible values

geolocation-approximate geolocation
1. denied denied
2. prompt denied
3. granted denied
4. prompt prompt
5. granted prompt
6. granted granted

When the user grants a geolocation request for approximate only, the resulting permission states will be (granted, prompt), since the user has been prompted for approximate geolocation but still hasn't made any decision about precise location.

On the other hand, when the user grants a gelocation request for precise (which in the current model allows the user to choose between approximate and precise), the permission states will be (granted,denied) if the user grants approximate and (granted,granted) if the user grants precise.

Note that the returned value on permissions.query() for geolocation is not the value of "geolocation":

geolocation-approximate geolocation query(geolocation) returns query(geolocation-approximate) returns
1. denied denied denied denied
2. prompt denied prompt prompt
3. granted denied granted granted
4. prompt prompt prompt prompt
5. granted prompt prompt prompt
6. granted granted granted granted

This seems kind of weird, but it maintains the very nice invariant that navigator.query() returns prompt/denied/granted iff getCurrentLocation prompts/throws/return.

In particular, this model reaches the following goals:

  1. Full backwards compatibility for sites that keep using getCurrentLocation without specifying an accuracyMode (but giving users the choice between approximate and precise location when granting permission).
  2. Enables sites to switch to approximate location only by using accuracyMode: 'approximate' and querying "geolocation-approximate"
  3. Allows users to choose between precise and approximate location even if the website asks for precise location only.
  4. Enables sites which use approximate location only to, in the future, upgrade to precise location (since when users are prompted for approximate location only, the state of "geolocation" remains prompt).

The model is detailed in the explainer.

@antosart
Copy link
Copy Markdown
Member

(And we are happy to consider suggestions or alternatives, of course! But we have thought about this for quite some time and in depth and we came to the conclusion that this is the easiest model that satisfies the properties above, and that it works quite nice at the end of the day. That is also reflected by our prototype implementation in chrome, which is relatively natural and straightforward because of the invariants we want to preserve, despite the model might seem complex at a first glance.)

@marcoscaceres
Copy link
Copy Markdown
Member

@antosart, please know I’m sympathetic and super appreciative of the amount of thinking and work that’s gone into this from you, @alvinjiooo, and other folks that have contributed thus far.

It feels like we’ve exhausted laying our use cases, which has been really thought-provoking and worthwhile.

Given the length of these discussions, what I’d like to do is spin up a Google doc outlining both approaches, so we can share with PING, Mozilla, and the WG to reach consensus.

I’ll share it with you all privately first to make sure it looks okay and captures all your points. Once I have your ok, we can send it out.

In the meantime, there’s still some editorial cleanup we can do to get the spec as close to ready to merge as possible.

Sound good?

@marcoscaceres
Copy link
Copy Markdown
Member

I've put the comparison report up on the Wiki.
https://github.com/w3c/geolocation/wiki/Approximate-Geolocation:-Permissions-Model-Comparison

Please take a look and we can share it from there if you all agree.

@antosart
Copy link
Copy Markdown
Member

Thanks! I will have a look. Please note that I'm also welcoming your input and happy to keep iterating in order to find a solution/compromise that is fine/acceptable for everyone.

@antosart
Copy link
Copy Markdown
Member

I have a couple of comments on https://github.com/w3c/geolocation/wiki/Approximate-Geolocation:-Permissions-Model-Comparison.

  1. Could you clarify in the WebKit model whether there is agreement with the core internals of the permission model (i.e. 6 internal permission states) or whether you are proposing something else?
  2. I think Scenario 2. is inaccurate. After a site calls navigator.getCurrentPosition() (i.e. after requesting precise), the internal state of the "geolocation" permission will be either "granted" or "denied". This means that the internal state will be one of the following: approx/precise = (granted/granted) or (granted/denied) or (denied/denied) and in all those cases the return values of permissions.query() for precise and approximate coincide. This means that if the site calls navigator.getCurrentPosition(), it destroys any queryable information on whether approximate or precise was granted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

TPAC2025 Topics for discussion at TPAC 2025

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Approximate geolocation

8 participants